feat(ui): use config for all numerical params

Centralize the initial/min/max/etc values for all numerical params. We used this for some but at some point stopped updating it.

All numerical params now use their respective configs. Far fewer hardcoded values throughout the app now.

Also updated the config types a bit to better accommodate slider vs number input constraints.
This commit is contained in:
psychedelicious 2024-01-07 13:21:19 +11:00
parent 6024fc7baf
commit 3428ea1b3c
29 changed files with 530 additions and 445 deletions

View File

@ -43,6 +43,16 @@ export type SDFeature =
| 'vae'
| 'hrf';
export type NumericalParameterConfig = {
initial: number;
sliderMin: number;
sliderMax: number;
numberInputMin: number;
numberInputMax: number;
fineStep: number;
coarseStep: number;
};
/**
* Configuration options for the InvokeAI UI.
* Distinct from system settings which may be changed inside the app.
@ -66,69 +76,32 @@ export type AppConfig = {
defaultModel?: string;
disabledControlNetModels: string[];
disabledControlNetProcessors: (keyof typeof CONTROLNET_PROCESSORS)[];
iterations: {
initial: number;
min: number;
sliderMax: number;
inputMax: number;
fineStep: number;
coarseStep: number;
};
width: {
initial: number;
min: number;
sliderMax: number;
inputMax: number;
fineStep: number;
coarseStep: number;
};
height: {
initial: number;
min: number;
sliderMax: number;
inputMax: number;
fineStep: number;
coarseStep: number;
};
steps: {
initial: number;
min: number;
sliderMax: number;
inputMax: number;
fineStep: number;
coarseStep: number;
};
guidance: {
initial: number;
min: number;
sliderMax: number;
inputMax: number;
fineStep: number;
coarseStep: number;
};
img2imgStrength: {
initial: number;
min: number;
sliderMax: number;
inputMax: number;
fineStep: number;
coarseStep: number;
};
hrfStrength: {
initial: number;
min: number;
sliderMax: number;
inputMax: number;
fineStep: number;
coarseStep: number;
};
// Core parameters
iterations: NumericalParameterConfig;
width: NumericalParameterConfig; // initial value comes from model
height: NumericalParameterConfig; // initial value comes from model
steps: NumericalParameterConfig;
guidance: NumericalParameterConfig;
cfgRescaleMultiplier: NumericalParameterConfig;
img2imgStrength: NumericalParameterConfig;
// Canvas
boundingBoxHeight: NumericalParameterConfig; // initial value comes from model
boundingBoxWidth: NumericalParameterConfig; // initial value comes from model
scaledBoundingBoxHeight: NumericalParameterConfig; // initial value comes from model
scaledBoundingBoxWidth: NumericalParameterConfig; // initial value comes from model
canvasCoherenceStrength: NumericalParameterConfig;
canvasCoherenceSteps: NumericalParameterConfig;
infillTileSize: NumericalParameterConfig;
infillPatchmatchDownscaleSize: NumericalParameterConfig;
// Misc advanced
clipSkip: NumericalParameterConfig; // slider and input max are ignored for this, because the values depend on the model
maskBlur: NumericalParameterConfig;
hrfStrength: NumericalParameterConfig;
dynamicPrompts: {
maxPrompts: {
initial: number;
min: number;
sliderMax: number;
inputMax: number;
maxPrompts: NumericalParameterConfig;
};
ca: {
weight: NumericalParameterConfig;
};
};
};

View File

@ -1,4 +1,4 @@
import { useAppDispatch } from 'app/store/storeHooks';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvControlGroup } from 'common/components/InvControl/InvControlGroup';
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
@ -17,10 +17,22 @@ type ParamControlAdapterWeightProps = {
const formatValue = (v: number) => v.toFixed(2);
const ParamControlAdapterWeight = ({ id }: ParamControlAdapterWeightProps) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const isEnabled = useControlAdapterIsEnabled(id);
const weight = useControlAdapterWeight(id);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const initial = useAppSelector((s) => s.config.sd.ca.weight.initial);
const sliderMin = useAppSelector((s) => s.config.sd.ca.weight.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.ca.weight.sliderMax);
const numberInputMin = useAppSelector(
(s) => s.config.sd.ca.weight.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.ca.weight.numberInputMax
);
const coarseStep = useAppSelector((s) => s.config.sd.ca.weight.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.ca.weight.fineStep);
const onChange = useCallback(
(weight: number) => {
dispatch(controlAdapterWeightChanged({ id, weight }));
@ -43,23 +55,23 @@ const ParamControlAdapterWeight = ({ id }: ParamControlAdapterWeightProps) => {
<InvSlider
value={weight}
onChange={onChange}
defaultValue={1}
min={0}
max={2}
step={0.05}
fineStep={0.01}
defaultValue={initial}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
marks={marks}
formatValue={formatValue}
/>
<InvNumberInput
value={weight}
onChange={onChange}
min={-1}
max={2}
step={0.05}
fineStep={0.01}
min={numberInputMin}
max={numberInputMax}
step={coarseStep}
fineStep={fineStep}
maxW={20}
defaultValue={1}
defaultValue={initial}
/>
</InvControl>
</InvControlGroup>

View File

@ -7,12 +7,17 @@ import { useTranslation } from 'react-i18next';
const ParamDynamicPromptsMaxPrompts = () => {
const maxPrompts = useAppSelector((s) => s.dynamicPrompts.maxPrompts);
const min = useAppSelector((s) => s.config.sd.dynamicPrompts.maxPrompts.min);
const sliderMin = useAppSelector(
(s) => s.config.sd.dynamicPrompts.maxPrompts.sliderMin
);
const sliderMax = useAppSelector(
(s) => s.config.sd.dynamicPrompts.maxPrompts.sliderMax
);
const inputMax = useAppSelector(
(s) => s.config.sd.dynamicPrompts.maxPrompts.inputMax
const numberInputMin = useAppSelector(
(s) => s.config.sd.dynamicPrompts.maxPrompts.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.dynamicPrompts.maxPrompts.numberInputMax
);
const initial = useAppSelector(
(s) => s.config.sd.dynamicPrompts.maxPrompts.initial
@ -36,14 +41,15 @@ const ParamDynamicPromptsMaxPrompts = () => {
renderInfoPopoverInPortal={false}
>
<InvSlider
min={min}
min={sliderMin}
max={sliderMax}
value={maxPrompts}
defaultValue={initial}
onChange={handleChange}
marks
withNumberInput
numberInputMax={inputMax}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
/>
</InvControl>
);

View File

@ -8,8 +8,14 @@ import { useTranslation } from 'react-i18next';
const ParamHrfStrength = () => {
const hrfStrength = useAppSelector((s) => s.hrf.hrfStrength);
const initial = useAppSelector((s) => s.config.sd.hrfStrength.initial);
const min = useAppSelector((s) => s.config.sd.hrfStrength.min);
const sliderMin = useAppSelector((s) => s.config.sd.hrfStrength.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.hrfStrength.sliderMax);
const numberInputMin = useAppSelector(
(s) => s.config.sd.hrfStrength.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.hrfStrength.numberInputMax
);
const coarseStep = useAppSelector((s) => s.config.sd.hrfStrength.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.hrfStrength.fineStep);
const dispatch = useAppDispatch();
@ -25,7 +31,7 @@ const ParamHrfStrength = () => {
return (
<InvControl label={t('parameters.denoisingStrength')}>
<InvSlider
min={min}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
@ -34,6 +40,8 @@ const ParamHrfStrength = () => {
onChange={onChange}
marks
withNumberInput
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
/>
</InvControl>
);

View File

@ -9,6 +9,28 @@ const ParamCFGRescaleMultiplier = () => {
const cfgRescaleMultiplier = useAppSelector(
(s) => s.generation.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
);
const numberInputMin = useAppSelector(
(s) => s.config.sd.cfgRescaleMultiplier.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.cfgRescaleMultiplier.numberInputMax
);
const coarseStep = useAppSelector(
(s) => s.config.sd.cfgRescaleMultiplier.coarseStep
);
const fineStep = useAppSelector(
(s) => s.config.sd.cfgRescaleMultiplier.fineStep
);
const dispatch = useAppDispatch();
const { t } = useTranslation();
@ -24,12 +46,14 @@ const ParamCFGRescaleMultiplier = () => {
>
<InvSlider
value={cfgRescaleMultiplier}
defaultValue={0}
min={0}
max={0.99}
step={0.1}
fineStep={0.01}
defaultValue={initial}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
onChange={handleChange}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
withNumberInput
marks
/>

View File

@ -8,7 +8,13 @@ import { useTranslation } from 'react-i18next';
const ParamClipSkip = () => {
const clipSkip = useAppSelector((s) => s.generation.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 dispatch = useAppDispatch();
@ -43,12 +49,15 @@ const ParamClipSkip = () => {
<InvControl label={t('parameters.clipSkip')} feature="clipSkip">
<InvSlider
value={clipSkip}
defaultValue={0}
min={0}
defaultValue={initial}
min={sliderMin}
max={max}
step={1}
step={coarseStep}
fineStep={fineStep}
onChange={handleClipSkipChange}
withNumberInput
numberInputMin={numberInputMin}
numberInputMax={max}
marks={sliderMarks}
/>
</InvControl>

View File

@ -2,21 +2,34 @@ import { useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import {
CANVAS_GRID_SIZE_COARSE,
CANVAS_GRID_SIZE_FINE,
} from 'features/canvas/store/constants';
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';
const ParamBoundingBoxWidth = () => {
const isStaging = useAppSelector(isStagingSelector);
const initial = useAppSelector(selectOptimalDimension);
const ctx = useImageSizeContext();
const ParamBoundingBoxHeight = () => {
const { t } = useTranslation();
const ctx = useImageSizeContext();
const isStaging = useAppSelector(isStagingSelector);
const optimalDimension = useAppSelector(selectOptimalDimension);
const sliderMin = useAppSelector(
(s) => s.config.sd.boundingBoxHeight.sliderMin
);
const sliderMax = useAppSelector(
(s) => s.config.sd.boundingBoxHeight.sliderMax
);
const numberInputMin = useAppSelector(
(s) => s.config.sd.boundingBoxHeight.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.boundingBoxHeight.numberInputMax
);
const coarseStep = useAppSelector(
(s) => s.config.sd.boundingBoxHeight.coarseStep
);
const fineStep = useAppSelector(
(s) => s.config.sd.boundingBoxHeight.fineStep
);
const onChange = useCallback(
(v: number) => {
ctx.heightChanged(v);
@ -27,19 +40,20 @@ const ParamBoundingBoxWidth = () => {
return (
<InvControl label={t('parameters.height')} isDisabled={isStaging}>
<InvSlider
min={64}
max={1536}
step={CANVAS_GRID_SIZE_COARSE}
fineStep={CANVAS_GRID_SIZE_FINE}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
value={ctx.height}
defaultValue={initial}
defaultValue={optimalDimension}
onChange={onChange}
marks
withNumberInput
numberInputMax={4096}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
/>
</InvControl>
);
};
export default memo(ParamBoundingBoxWidth);
export default memo(ParamBoundingBoxHeight);

View File

@ -2,21 +2,32 @@ import { useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import {
CANVAS_GRID_SIZE_COARSE,
CANVAS_GRID_SIZE_FINE,
} from 'features/canvas/store/constants';
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';
const ParamBoundingBoxWidth = () => {
const isStaging = useAppSelector(isStagingSelector);
const initial = useAppSelector(selectOptimalDimension);
const ctx = useImageSizeContext();
const { t } = useTranslation();
const ctx = useImageSizeContext();
const isStaging = useAppSelector(isStagingSelector);
const optimalDimension = useAppSelector(selectOptimalDimension);
const sliderMin = useAppSelector(
(s) => s.config.sd.boundingBoxWidth.sliderMin
);
const sliderMax = useAppSelector(
(s) => s.config.sd.boundingBoxWidth.sliderMax
);
const numberInputMin = useAppSelector(
(s) => s.config.sd.boundingBoxWidth.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.boundingBoxWidth.numberInputMax
);
const coarseStep = useAppSelector(
(s) => s.config.sd.boundingBoxWidth.coarseStep
);
const fineStep = useAppSelector((s) => s.config.sd.boundingBoxWidth.fineStep);
const onChange = useCallback(
(v: number) => {
ctx.widthChanged(v);
@ -27,15 +38,16 @@ const ParamBoundingBoxWidth = () => {
return (
<InvControl label={t('parameters.width')} isDisabled={isStaging}>
<InvSlider
min={64}
max={1536}
step={CANVAS_GRID_SIZE_COARSE}
fineStep={CANVAS_GRID_SIZE_FINE}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
value={ctx.width}
defaultValue={initial}
defaultValue={optimalDimension}
onChange={onChange}
withNumberInput
numberInputMax={4096}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
marks
/>
</InvControl>

View File

@ -10,6 +10,28 @@ const ParamCanvasCoherenceSteps = () => {
const canvasCoherenceSteps = useAppSelector(
(s) => s.generation.canvasCoherenceSteps
);
const initial = useAppSelector(
(s) => s.config.sd.canvasCoherenceSteps.initial
);
const sliderMin = useAppSelector(
(s) => s.config.sd.canvasCoherenceSteps.sliderMin
);
const sliderMax = useAppSelector(
(s) => s.config.sd.canvasCoherenceSteps.sliderMax
);
const numberInputMin = useAppSelector(
(s) => s.config.sd.canvasCoherenceSteps.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.canvasCoherenceSteps.numberInputMax
);
const coarseStep = useAppSelector(
(s) => s.config.sd.canvasCoherenceSteps.coarseStep
);
const fineStep = useAppSelector(
(s) => s.config.sd.canvasCoherenceSteps.fineStep
);
const { t } = useTranslation();
const handleChange = useCallback(
@ -25,14 +47,16 @@ const ParamCanvasCoherenceSteps = () => {
feature="compositingCoherenceSteps"
>
<InvSlider
min={1}
max={100}
step={1}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
value={canvasCoherenceSteps}
defaultValue={20}
defaultValue={initial}
onChange={handleChange}
withNumberInput
numberInputMax={999}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
marks
/>
</InvControl>

View File

@ -6,9 +6,20 @@ 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 { t } = useTranslation();
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);
const numberInputMin = useAppSelector(
(s) => s.config.sd.maskBlur.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.maskBlur.numberInputMax
);
const coarseStep = useAppSelector((s) => s.config.sd.maskBlur.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.maskBlur.fineStep);
const handleChange = useCallback(
(v: number) => {
@ -20,14 +31,17 @@ const ParamMaskBlur = () => {
return (
<InvControl label={t('parameters.maskBlur')} feature="compositingBlur">
<InvSlider
min={0}
max={64}
min={sliderMin}
max={sliderMax}
value={maskBlur}
defaultValue={16}
defaultValue={initial}
onChange={handleChange}
marks
withNumberInput
numberInputMax={512}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
step={coarseStep}
fineStep={fineStep}
/>
</InvControl>
);

View File

@ -11,6 +11,27 @@ const ParamInfillPatchmatchDownscaleSize = () => {
const infillPatchmatchDownscaleSize = useAppSelector(
(s) => s.generation.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
);
const numberInputMin = useAppSelector(
(s) => s.config.sd.infillPatchmatchDownscaleSize.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.infillPatchmatchDownscaleSize.numberInputMax
);
const coarseStep = useAppSelector(
(s) => s.config.sd.infillPatchmatchDownscaleSize.coarseStep
);
const fineStep = useAppSelector(
(s) => s.config.sd.infillPatchmatchDownscaleSize.fineStep
);
const { t } = useTranslation();
@ -27,12 +48,16 @@ const ParamInfillPatchmatchDownscaleSize = () => {
label={t('parameters.patchmatchDownScaleSize')}
>
<InvSlider
min={1}
max={10}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
value={infillPatchmatchDownscaleSize}
defaultValue={1}
defaultValue={initial}
onChange={handleChange}
withNumberInput
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
marks
/>
</InvControl>

View File

@ -8,6 +8,20 @@ import { useTranslation } from 'react-i18next';
const ParamInfillTileSize = () => {
const dispatch = useAppDispatch();
const infillTileSize = useAppSelector((s) => s.generation.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);
const numberInputMin = useAppSelector(
(s) => s.config.sd.infillTileSize.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.infillTileSize.numberInputMax
);
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 { t } = useTranslation();
@ -25,12 +39,15 @@ const ParamInfillTileSize = () => {
label={t('parameters.tileSize')}
>
<InvSlider
min={16}
max={64}
numberInputMax={256}
min={sliderMin}
max={sliderMax}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
value={infillTileSize}
defaultValue={32}
defaultValue={initial}
onChange={handleChange}
step={coarseStep}
fineStep={fineStep}
withNumberInput
marks
/>

View File

@ -2,15 +2,12 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { setScaledBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
import {
CANVAS_GRID_SIZE_COARSE,
CANVAS_GRID_SIZE_FINE,
} from 'features/canvas/store/constants';
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
const ParamScaledHeight = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const optimalDimension = useAppSelector(selectOptimalDimension);
const isManual = useAppSelector(
@ -19,8 +16,24 @@ const ParamScaledHeight = () => {
const height = useAppSelector(
(s) => s.canvas.scaledBoundingBoxDimensions.height
);
const { t } = useTranslation();
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
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.scaledBoundingBoxHeight.numberInputMax
);
const coarseStep = useAppSelector(
(s) => s.config.sd.scaledBoundingBoxHeight.coarseStep
);
const fineStep = useAppSelector(
(s) => s.config.sd.scaledBoundingBoxHeight.fineStep
);
const onChange = useCallback(
(height: number) => {
@ -29,23 +42,20 @@ const ParamScaledHeight = () => {
[dispatch]
);
const onReset = useCallback(() => {
dispatch(setScaledBoundingBoxDimensions({ height: optimalDimension }));
}, [dispatch, optimalDimension]);
return (
<InvControl isDisabled={!isManual} label={t('parameters.scaledHeight')}>
<InvSlider
min={64}
max={1536}
step={CANVAS_GRID_SIZE_COARSE}
fineStep={CANVAS_GRID_SIZE_FINE}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
value={height}
onChange={onChange}
marks
withNumberInput
numberInputMax={4096}
onReset={onReset}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
defaultValue={optimalDimension}
/>
</InvControl>
);

View File

@ -2,17 +2,13 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { setScaledBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
import {
CANVAS_GRID_SIZE_COARSE,
CANVAS_GRID_SIZE_FINE,
} from 'features/canvas/store/constants';
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
const ParamScaledWidth = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const dispatch = useAppDispatch();
const optimalDimension = useAppSelector(selectOptimalDimension);
const isManual = useAppSelector(
(s) => s.canvas.boundingBoxScaleMethod === 'manual'
@ -20,7 +16,24 @@ const ParamScaledWidth = () => {
const width = useAppSelector(
(s) => s.canvas.scaledBoundingBoxDimensions.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
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.scaledBoundingBoxWidth.numberInputMax
);
const coarseStep = useAppSelector(
(s) => s.config.sd.scaledBoundingBoxWidth.coarseStep
);
const fineStep = useAppSelector(
(s) => s.config.sd.scaledBoundingBoxWidth.fineStep
);
const onChange = useCallback(
(width: number) => {
dispatch(setScaledBoundingBoxDimensions({ width }));
@ -28,23 +41,20 @@ const ParamScaledWidth = () => {
[dispatch]
);
const onReset = useCallback(() => {
dispatch(setScaledBoundingBoxDimensions({ width: optimalDimension }));
}, [dispatch, optimalDimension]);
return (
<InvControl isDisabled={!isManual} label={t('parameters.scaledWidth')}>
<InvSlider
min={64}
max={1536}
step={CANVAS_GRID_SIZE_COARSE}
fineStep={CANVAS_GRID_SIZE_FINE}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
value={width}
onChange={onChange}
numberInputMax={4096}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
defaultValue={optimalDimension}
marks
withNumberInput
onReset={onReset}
/>
</InvControl>
);

View File

@ -7,17 +7,22 @@ import { useTranslation } from 'react-i18next';
const ParamCFGScale = () => {
const cfgScale = useAppSelector((s) => s.generation.cfgScale);
const min = useAppSelector((s) => s.config.sd.guidance.min);
const inputMax = useAppSelector((s) => s.config.sd.guidance.inputMax);
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
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.guidance.numberInputMax
);
const coarseStep = useAppSelector((s) => s.config.sd.guidance.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.guidance.fineStep);
const initial = useAppSelector((s) => s.config.sd.guidance.initial);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const marks = useMemo(
() => [min, Math.floor(sliderMax / 2), sliderMax],
[sliderMax, min]
() => [sliderMin, Math.floor(sliderMax / 2), sliderMax],
[sliderMax, sliderMin]
);
const onChange = useCallback(
(v: number) => dispatch(setCfgScale(v)),
@ -29,14 +34,15 @@ const ParamCFGScale = () => {
<InvSlider
value={cfgScale}
defaultValue={initial}
min={min}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
withNumberInput
marks={marks}
numberInputMax={inputMax}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
/>
</InvControl>
);

View File

@ -1,6 +1,5 @@
import { useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
@ -11,9 +10,14 @@ export const ParamHeight = memo(() => {
const { t } = useTranslation();
const ctx = useImageSizeContext();
const optimalDimension = useAppSelector(selectOptimalDimension);
const min = useAppSelector((s) => s.config.sd.height.min);
const sliderMin = useAppSelector((s) => s.config.sd.height.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.height.sliderMax);
const inputMax = useAppSelector((s) => s.config.sd.height.inputMax);
const numberInputMin = useAppSelector(
(s) => s.config.sd.height.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.height.numberInputMax
);
const coarseStep = useAppSelector((s) => s.config.sd.height.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.height.fineStep);
@ -25,8 +29,8 @@ export const ParamHeight = memo(() => {
);
const marks = useMemo(
() => [min, optimalDimension, sliderMax],
[min, optimalDimension, sliderMax]
() => [sliderMin, optimalDimension, sliderMax],
[sliderMin, optimalDimension, sliderMax]
);
return (
@ -35,20 +39,14 @@ export const ParamHeight = memo(() => {
value={ctx.height}
defaultValue={optimalDimension}
onChange={onChange}
min={min}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
marks={marks}
/>
<InvNumberInput
value={ctx.height}
onChange={onChange}
min={min}
max={inputMax}
step={coarseStep}
fineStep={fineStep}
defaultValue={optimalDimension}
withNumberInput
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
/>
</InvControl>
);

View File

@ -1,26 +1,28 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import {
clampSymmetrySteps,
setSteps,
} from 'features/parameters/store/generationSlice';
import { setSteps } from 'features/parameters/store/generationSlice';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
const ParamSteps = () => {
const steps = useAppSelector((s) => s.generation.steps);
const initial = useAppSelector((s) => s.config.sd.steps.initial);
const min = useAppSelector((s) => s.config.sd.steps.min);
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
const inputMax = useAppSelector((s) => s.config.sd.steps.inputMax);
const numberInputMin = useAppSelector(
(s) => s.config.sd.steps.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.steps.numberInputMax
);
const coarseStep = useAppSelector((s) => s.config.sd.steps.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.steps.fineStep);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const marks = useMemo(
() => [min, Math.floor(sliderMax / 2), sliderMax],
[sliderMax, min]
() => [sliderMin, Math.floor(sliderMax / 2), sliderMax],
[sliderMax, sliderMin]
);
const onChange = useCallback(
(v: number) => {
@ -29,24 +31,20 @@ const ParamSteps = () => {
[dispatch]
);
const onBlur = useCallback(() => {
dispatch(clampSymmetrySteps());
}, [dispatch]);
return (
<InvControl label={t('parameters.steps')} feature="paramSteps">
<InvSlider
value={steps}
defaultValue={initial}
min={min}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
onBlur={onBlur}
withNumberInput
marks={marks}
numberInputMax={inputMax}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
/>
</InvControl>
);

View File

@ -1,6 +1,5 @@
import { useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
@ -11,9 +10,14 @@ export const ParamWidth = memo(() => {
const { t } = useTranslation();
const ctx = useImageSizeContext();
const optimalDimension = useAppSelector(selectOptimalDimension);
const min = useAppSelector((s) => s.config.sd.width.min);
const sliderMin = useAppSelector((s) => s.config.sd.width.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.width.sliderMax);
const inputMax = useAppSelector((s) => s.config.sd.width.inputMax);
const numberInputMin = useAppSelector(
(s) => s.config.sd.width.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.width.numberInputMax
);
const coarseStep = useAppSelector((s) => s.config.sd.width.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.width.fineStep);
@ -25,8 +29,8 @@ export const ParamWidth = memo(() => {
);
const marks = useMemo(
() => [min, optimalDimension, sliderMax],
[min, optimalDimension, sliderMax]
() => [sliderMin, optimalDimension, sliderMax],
[sliderMin, optimalDimension, sliderMax]
);
return (
@ -35,20 +39,14 @@ export const ParamWidth = memo(() => {
value={ctx.width}
onChange={onChange}
defaultValue={optimalDimension}
min={min}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
marks={marks}
/>
<InvNumberInput
value={ctx.width}
onChange={onChange}
min={min}
max={inputMax}
step={coarseStep}
fineStep={fineStep}
defaultValue={optimalDimension}
withNumberInput
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
/>
</InvControl>
);

View File

@ -10,11 +10,18 @@ const marks = [0, 0.5, 1];
const ImageToImageStrength = () => {
const img2imgStrength = useAppSelector((s) => s.generation.img2imgStrength);
const initial = useAppSelector((s) => s.config.sd.img2imgStrength.initial);
const min = useAppSelector((s) => s.config.sd.img2imgStrength.min);
const sliderMin = useAppSelector(
(s) => s.config.sd.img2imgStrength.sliderMin
);
const sliderMax = useAppSelector(
(s) => s.config.sd.img2imgStrength.sliderMax
);
const inputMax = useAppSelector((s) => s.config.sd.img2imgStrength.inputMax);
const numberInputMin = useAppSelector(
(s) => s.config.sd.img2imgStrength.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.img2imgStrength.numberInputMax
);
const coarseStep = useAppSelector(
(s) => s.config.sd.img2imgStrength.coarseStep
);
@ -35,14 +42,15 @@ const ImageToImageStrength = () => {
<InvSlider
step={coarseStep}
fineStep={fineStep}
min={min}
min={sliderMin}
max={sliderMax}
onChange={handleChange}
value={img2imgStrength}
defaultValue={initial}
marks={marks}
withNumberInput
numberInputMax={inputMax}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
/>
</InvControl>
);

View File

@ -1,42 +0,0 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { setHorizontalSymmetrySteps } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
const ParamSymmetryHorizontal = () => {
const horizontalSymmetrySteps = useAppSelector(
(s) => s.generation.horizontalSymmetrySteps
);
const steps = useAppSelector((s) => s.generation.steps);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const handleChange = useCallback(
(v: number) => {
dispatch(setHorizontalSymmetrySteps(v));
},
[dispatch]
);
return (
<InvControl label={t('parameters.hSymmetryStep')}>
<InvSlider
value={horizontalSymmetrySteps}
defaultValue={0}
onChange={handleChange}
min={0}
max={steps}
step={1}
withNumberInput
marks
/>
</InvControl>
);
};
export default memo(ParamSymmetryHorizontal);

View File

@ -1,28 +0,0 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSwitch } from 'common/components/InvSwitch/wrapper';
import { setShouldUseSymmetry } from 'features/parameters/store/generationSlice';
import type { ChangeEvent } from 'react';
import { memo, useCallback } from 'react';
const ParamSymmetryToggle = () => {
const shouldUseSymmetry = useAppSelector(
(s) => s.generation.shouldUseSymmetry
);
const dispatch = useAppDispatch();
const handleChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
dispatch(setShouldUseSymmetry(e.target.checked));
},
[dispatch]
);
return (
<InvControl label="Enable Symmetry">
<InvSwitch isChecked={shouldUseSymmetry} onChange={handleChange} />
</InvControl>
);
};
export default memo(ParamSymmetryToggle);

View File

@ -1,42 +0,0 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { setVerticalSymmetrySteps } from 'features/parameters/store/generationSlice';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
const ParamSymmetryVertical = () => {
const verticalSymmetrySteps = useAppSelector(
(s) => s.generation.verticalSymmetrySteps
);
const steps = useAppSelector((s) => s.generation.steps);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const handleChange = useCallback(
(v: number) => {
dispatch(setVerticalSymmetrySteps(v));
},
[dispatch]
);
return (
<InvControl label={t('parameters.vSymmetryStep')}>
<InvSlider
value={verticalSymmetrySteps}
defaultValue={0}
onChange={handleChange}
min={0}
max={steps}
step={1}
withNumberInput
marks
/>
</InvControl>
);
};
export default memo(ParamSymmetryVertical);

View File

@ -35,7 +35,6 @@ export const initialGenerationState: GenerationState = {
img2imgStrength: 0.75,
infillMethod: 'patchmatch',
iterations: 1,
perlin: 0,
positivePrompt: '',
negativePrompt: '',
scheduler: 'euler',
@ -45,19 +44,12 @@ export const initialGenerationState: GenerationState = {
canvasCoherenceSteps: 20,
canvasCoherenceStrength: 0.3,
seed: 0,
seedWeights: '',
shouldFitToWidthHeight: true,
shouldGenerateVariations: false,
shouldRandomizeSeed: true,
steps: 50,
threshold: 0,
infillTileSize: 32,
infillPatchmatchDownscaleSize: 1,
variationAmount: 0.1,
width: 512,
shouldUseSymmetry: false,
horizontalSymmetrySteps: 0,
verticalSymmetrySteps: 0,
model: null,
vae: null,
vaePrecision: 'fp32',
@ -85,18 +77,6 @@ export const generationSlice = createSlice({
setSteps: (state, action: PayloadAction<number>) => {
state.steps = action.payload;
},
clampSymmetrySteps: (state) => {
state.horizontalSymmetrySteps = clamp(
state.horizontalSymmetrySteps,
0,
state.steps
);
state.verticalSymmetrySteps = clamp(
state.verticalSymmetrySteps,
0,
state.steps
);
},
setCfgScale: (state, action: PayloadAction<ParameterCFGScale>) => {
state.cfgScale = action.payload;
},
@ -106,12 +86,6 @@ export const generationSlice = createSlice({
) => {
state.cfgRescaleMultiplier = action.payload;
},
setThreshold: (state, action: PayloadAction<number>) => {
state.threshold = action.payload;
},
setPerlin: (state, action: PayloadAction<number>) => {
state.perlin = action.payload;
},
setScheduler: (state, action: PayloadAction<ParameterScheduler>) => {
state.scheduler = action.payload;
},
@ -134,17 +108,6 @@ export const generationSlice = createSlice({
resetSeed: (state) => {
state.seed = -1;
},
setShouldGenerateVariations: (state, action: PayloadAction<boolean>) => {
state.shouldGenerateVariations = action.payload;
},
setVariationAmount: (state, action: PayloadAction<number>) => {
state.variationAmount = action.payload;
},
setSeedWeights: (state, action: PayloadAction<string>) => {
state.seedWeights = action.payload;
state.shouldGenerateVariations = true;
state.variationAmount = 0;
},
resetParametersState: (state) => {
return {
...state,
@ -190,15 +153,6 @@ export const generationSlice = createSlice({
) => {
state.infillPatchmatchDownscaleSize = action.payload;
},
setShouldUseSymmetry: (state, action: PayloadAction<boolean>) => {
state.shouldUseSymmetry = action.payload;
},
setHorizontalSymmetrySteps: (state, action: PayloadAction<number>) => {
state.horizontalSymmetrySteps = action.payload;
},
setVerticalSymmetrySteps: (state, action: PayloadAction<number>) => {
state.verticalSymmetrySteps = action.payload;
},
initialImageChanged: (state, action: PayloadAction<ImageDTO>) => {
const { image_name, width, height } = action.payload;
state.initialImage = { imageName: image_name, width, height };
@ -282,7 +236,6 @@ export const generationSlice = createSlice({
});
export const {
clampSymmetrySteps,
clearInitialImage,
resetParametersState,
resetSeed,
@ -291,7 +244,6 @@ export const {
setImg2imgStrength,
setInfillMethod,
setIterations,
setPerlin,
setPositivePrompt,
setNegativePrompt,
setScheduler,
@ -301,18 +253,11 @@ export const {
setCanvasCoherenceSteps,
setCanvasCoherenceStrength,
setSeed,
setSeedWeights,
setShouldFitToWidthHeight,
setShouldGenerateVariations,
setShouldRandomizeSeed,
setSteps,
setThreshold,
setInfillTileSize,
setInfillPatchmatchDownscaleSize,
setVariationAmount,
setShouldUseSymmetry,
setHorizontalSymmetrySteps,
setVerticalSymmetrySteps,
initialImageChanged,
modelChanged,
vaeSelected,

View File

@ -26,7 +26,6 @@ export interface GenerationState {
infillMethod: string;
initialImage?: { imageName: string; width: number; height: number };
iterations: number;
perlin: number;
positivePrompt: ParameterPositivePrompt;
negativePrompt: ParameterNegativePrompt;
scheduler: ParameterScheduler;
@ -36,19 +35,12 @@ export interface GenerationState {
canvasCoherenceSteps: number;
canvasCoherenceStrength: ParameterStrength;
seed: ParameterSeed;
seedWeights: string;
shouldFitToWidthHeight: boolean;
shouldGenerateVariations: boolean;
shouldRandomizeSeed: boolean;
steps: ParameterSteps;
threshold: number;
infillTileSize: number;
infillPatchmatchDownscaleSize: number;
variationAmount: number;
width: ParameterWidth;
shouldUseSymmetry: boolean;
horizontalSymmetrySteps: number;
verticalSymmetrySteps: number;
model: ParameterModel | null;
vae: ParameterVAEModel | null;
vaePrecision: ParameterPrecision;

View File

@ -1,7 +1,6 @@
import { enqueueRequested } from 'app/store/actions';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue';
import { clampSymmetrySteps } from 'features/parameters/store/generationSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useCallback, useMemo } from 'react';
import { useEnqueueBatchMutation } from 'services/api/endpoints/queue';
@ -18,7 +17,6 @@ export const useQueueBack = () => {
if (isDisabled) {
return;
}
dispatch(clampSymmetrySteps());
dispatch(enqueueRequested({ tabName, prepend: false }));
}, [dispatch, isDisabled, tabName]);

View File

@ -1,7 +1,6 @@
import { enqueueRequested } from 'app/store/actions';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue';
import { clampSymmetrySteps } from 'features/parameters/store/generationSlice';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useCallback, useMemo } from 'react';
@ -24,7 +23,6 @@ export const useQueueFront = () => {
if (isDisabled) {
return;
}
dispatch(clampSymmetrySteps());
dispatch(enqueueRequested({ tabName, prepend: true }));
}, [dispatch, isDisabled, tabName]);

View File

@ -9,15 +9,20 @@ const ParamSDXLRefinerCFGScale = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const refinerCFGScale = useAppSelector((s) => s.sdxl.refinerCFGScale);
const min = useAppSelector((s) => s.config.sd.guidance.min);
const inputMax = useAppSelector((s) => s.config.sd.guidance.inputMax);
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
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.guidance.numberInputMax
);
const coarseStep = useAppSelector((s) => s.config.sd.guidance.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.guidance.fineStep);
const initial = useAppSelector((s) => s.config.sd.guidance.initial);
const marks = useMemo(
() => [min, Math.floor(sliderMax / 2), sliderMax],
[sliderMax, min]
() => [sliderMin, Math.floor(sliderMax / 2), sliderMax],
[sliderMax, sliderMin]
);
const onChange = useCallback(
@ -30,13 +35,14 @@ const ParamSDXLRefinerCFGScale = () => {
<InvSlider
value={refinerCFGScale}
defaultValue={initial}
min={min}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
withNumberInput
numberInputMax={inputMax}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
marks={marks}
/>
</InvControl>

View File

@ -10,15 +10,20 @@ const ParamSDXLRefinerSteps = () => {
const dispatch = useAppDispatch();
const refinerSteps = useAppSelector((s) => s.sdxl.refinerSteps);
const initial = useAppSelector((s) => s.config.sd.steps.initial);
const min = useAppSelector((s) => s.config.sd.steps.min);
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
const inputMax = useAppSelector((s) => s.config.sd.steps.inputMax);
const numberInputMin = useAppSelector(
(s) => s.config.sd.steps.numberInputMin
);
const numberInputMax = useAppSelector(
(s) => s.config.sd.steps.numberInputMax
);
const coarseStep = useAppSelector((s) => s.config.sd.steps.coarseStep);
const fineStep = useAppSelector((s) => s.config.sd.steps.fineStep);
const marks = useMemo(
() => [min, Math.floor(sliderMax / 2), sliderMax],
[sliderMax, min]
() => [sliderMin, Math.floor(sliderMax / 2), sliderMax],
[sliderMax, sliderMin]
);
const onChange = useCallback(
@ -33,14 +38,15 @@ const ParamSDXLRefinerSteps = () => {
<InvSlider
value={refinerSteps}
defaultValue={initial}
min={min}
min={sliderMin}
max={sliderMax}
step={coarseStep}
fineStep={fineStep}
onChange={onChange}
withNumberInput
marks={marks}
numberInputMax={inputMax}
numberInputMin={numberInputMin}
numberInputMax={numberInputMax}
/>
</InvControl>
);

View File

@ -1,9 +1,23 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import type { AppConfig, PartialAppConfig } from 'app/types/invokeai';
import type {
AppConfig,
NumericalParameterConfig,
PartialAppConfig,
} from 'app/types/invokeai';
import { merge } from 'lodash-es';
const baseDimensionConfig: NumericalParameterConfig = {
initial: 512, // determined by model selection, unused in practice
sliderMin: 64,
sliderMax: 1536,
numberInputMin: 64,
numberInputMax: 4096,
fineStep: 8,
coarseStep: 64,
};
export const initialConfigState: AppConfig = {
shouldUpdateImagesOnConnect: false,
shouldFetchMetadataFromApi: false,
@ -24,66 +38,138 @@ export const initialConfigState: AppConfig = {
disabledControlNetProcessors: [],
iterations: {
initial: 1,
min: 1,
sliderMin: 1,
sliderMax: 1000,
inputMax: 10000,
numberInputMin: 1,
numberInputMax: 10000,
fineStep: 1,
coarseStep: 1,
},
width: {
initial: 512,
min: 64,
sliderMax: 1536,
inputMax: 4096,
fineStep: 8,
coarseStep: 64,
},
height: {
initial: 512,
min: 64,
sliderMax: 1536,
inputMax: 4096,
fineStep: 8,
coarseStep: 64,
},
width: { ...baseDimensionConfig },
height: { ...baseDimensionConfig },
boundingBoxWidth: { ...baseDimensionConfig },
boundingBoxHeight: { ...baseDimensionConfig },
scaledBoundingBoxWidth: { ...baseDimensionConfig },
scaledBoundingBoxHeight: { ...baseDimensionConfig },
steps: {
initial: 30,
min: 1,
sliderMin: 1,
sliderMax: 100,
inputMax: 500,
numberInputMin: 1,
numberInputMax: 500,
fineStep: 1,
coarseStep: 1,
},
guidance: {
initial: 7,
min: 1,
sliderMin: 1,
sliderMax: 20,
inputMax: 200,
numberInputMin: 1,
numberInputMax: 200,
fineStep: 0.1,
coarseStep: 0.5,
},
img2imgStrength: {
initial: 0.7,
min: 0,
sliderMin: 0,
sliderMax: 1,
inputMax: 1,
numberInputMin: 0,
numberInputMax: 1,
fineStep: 0.01,
coarseStep: 0.05,
},
canvasCoherenceStrength: {
initial: 0.3,
sliderMin: 0,
sliderMax: 1,
numberInputMin: 0,
numberInputMax: 1,
fineStep: 0.01,
coarseStep: 0.05,
},
hrfStrength: {
initial: 0.45,
min: 0,
sliderMin: 0,
sliderMax: 1,
inputMax: 1,
numberInputMin: 0,
numberInputMax: 1,
fineStep: 0.01,
coarseStep: 0.05,
},
canvasCoherenceSteps: {
initial: 20,
sliderMin: 1,
sliderMax: 100,
numberInputMin: 1,
numberInputMax: 999,
fineStep: 1,
coarseStep: 1,
},
cfgRescaleMultiplier: {
initial: 0,
sliderMin: 0,
sliderMax: 0.99,
numberInputMin: 0,
numberInputMax: 0.99,
fineStep: 0.05,
coarseStep: 0.1,
},
clipSkip: {
initial: 0,
sliderMin: 0,
sliderMax: 12, // determined by model selection, unused in practice
numberInputMin: 0,
numberInputMax: 12, // determined by model selection, unused in practice
fineStep: 1,
coarseStep: 1,
},
infillPatchmatchDownscaleSize: {
initial: 1,
sliderMin: 1,
sliderMax: 10,
numberInputMin: 1,
numberInputMax: 10,
fineStep: 1,
coarseStep: 1,
},
infillTileSize: {
initial: 32,
sliderMin: 16,
sliderMax: 64,
numberInputMin: 16,
numberInputMax: 256,
fineStep: 1,
coarseStep: 1,
},
maskBlur: {
initial: 16,
sliderMin: 0,
sliderMax: 64,
numberInputMin: 0,
numberInputMax: 512,
fineStep: 1,
coarseStep: 1,
},
ca: {
weight: {
initial: 1,
sliderMin: 0,
sliderMax: 2,
numberInputMin: -1,
numberInputMax: 2,
fineStep: 0.01,
coarseStep: 0.05,
},
},
dynamicPrompts: {
maxPrompts: {
initial: 100,
min: 1,
sliderMin: 1,
sliderMax: 1000,
inputMax: 10000,
numberInputMin: 1,
numberInputMax: 10000,
fineStep: 1,
coarseStep: 10,
},
},
},