diff --git a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamCreativity.tsx b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamCreativity.tsx
new file mode 100644
index 0000000000..f53058224e
--- /dev/null
+++ b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamCreativity.tsx
@@ -0,0 +1,55 @@
+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 { memo, useCallback, useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+
+const ParamCreativity = () => {
+ const steps = useAppSelector((s) => s.generation.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);
+ 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(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
+ const onChange = useCallback(
+ (v: number) => {
+ dispatch(setSteps(v));
+ },
+ [dispatch]
+ );
+
+ return (
+
+
+ Creativity
+
+
+
+
+ );
+};
+
+export default memo(ParamCreativity);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamSharpness.tsx b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamSharpness.tsx
new file mode 100644
index 0000000000..747d743d59
--- /dev/null
+++ b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamSharpness.tsx
@@ -0,0 +1,55 @@
+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 { memo, useCallback, useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+
+const ParamSharpness = () => {
+ const steps = useAppSelector((s) => s.generation.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);
+ 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(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
+ const onChange = useCallback(
+ (v: number) => {
+ dispatch(setSteps(v));
+ },
+ [dispatch]
+ );
+
+ return (
+
+
+ Sharpness
+
+
+
+
+ );
+};
+
+export default memo(ParamSharpness);
diff --git a/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamStructure.tsx b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamStructure.tsx
new file mode 100644
index 0000000000..cc55bfea50
--- /dev/null
+++ b/invokeai/frontend/web/src/features/parameters/components/Upscale/ParamStructure.tsx
@@ -0,0 +1,55 @@
+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 { memo, useCallback, useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+
+const ParamStructure = () => {
+ const steps = useAppSelector((s) => s.generation.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);
+ 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(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
+ const onChange = useCallback(
+ (v: number) => {
+ dispatch(setSteps(v));
+ },
+ [dispatch]
+ );
+
+ return (
+
+
+ Structure
+
+
+
+
+ );
+};
+
+export default memo(ParamStructure);
diff --git a/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts b/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts
index 0fb0fdf1d3..a4d8fbf3af 100644
--- a/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts
+++ b/invokeai/frontend/web/src/features/parameters/store/upscaleSlice.ts
@@ -14,7 +14,7 @@ interface UpscaleState {
const initialUpscaleState: UpscaleState = {
_version: 1,
upscaleModel: null,
- upscaleInitialImage: null
+ upscaleInitialImage: null,
};
export const upscaleSlice = createSlice({
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx
index 087efba616..ee358df188 100644
--- a/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx
+++ b/invokeai/frontend/web/src/features/settingsAccordions/components/AdvancedSettingsAccordion/AdvancedSettingsAccordion.tsx
@@ -14,6 +14,10 @@ import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/
import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useGetModelConfigQuery } from 'services/api/endpoints/models';
+import { activeTabNameSelector } from '../../../ui/store/uiSelectors';
+import { ParamSeedNumberInput } from '../../../parameters/components/Seed/ParamSeedNumberInput';
+import { ParamSeedRandomize } from '../../../parameters/components/Seed/ParamSeedRandomize';
+import { ParamSeedShuffle } from '../../../parameters/components/Seed/ParamSeedShuffle';
const formLabelProps: FormLabelProps = {
minW: '9.2rem',
@@ -26,6 +30,8 @@ const formLabelProps2: FormLabelProps = {
export const AdvancedSettingsAccordion = memo(() => {
const vaeKey = useAppSelector((state) => state.generation.vae?.key);
const { currentData: vaeConfig } = useGetModelConfigQuery(vaeKey ?? skipToken);
+ const activeTabName = useAppSelector(activeTabNameSelector);
+
const selectBadges = useMemo(
() =>
createMemoizedSelector(selectGenerationSlice, (generation) => {
@@ -48,9 +54,12 @@ export const AdvancedSettingsAccordion = memo(() => {
if (generation.seamlessXAxis || generation.seamlessYAxis) {
badges.push('seamless');
}
+ if (activeTabName === 'upscaling' && !generation.shouldRandomizeSeed) {
+ badges.push('Manual Seed');
+ }
return badges;
}),
- [vaeConfig]
+ [vaeConfig, activeTabName]
);
const badges = useAppSelector(selectBadges);
const { t } = useTranslation();
@@ -66,16 +75,27 @@ export const AdvancedSettingsAccordion = memo(() => {
-
-
-
-
-
-
-
-
-
-
+ {activeTabName === 'upscaling' && (
+
+
+
+
+
+ )}
+ {activeTabName !== 'upscaling' && (
+ <>
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
);
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion.tsx
index 3dc1c3d2a8..e7d45d043d 100644
--- a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion.tsx
+++ b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSettingsAccordion.tsx
@@ -1,24 +1,58 @@
-import { Flex, StandaloneAccordion } from '@invoke-ai/ui-library';
+import { Expander, Flex, StandaloneAccordion } from '@invoke-ai/ui-library';
import { useStandaloneAccordionToggle } from 'features/settingsAccordions/hooks/useStandaloneAccordionToggle';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import ParamSpandrelModel from '../../../parameters/components/Upscale/ParamSpandrelModel';
import { UpscaleInitialImage } from './UpscaleInitialImage';
+import { UpscaleSizeDetails } from './UpscaleSizeDetails';
+import { useExpanderToggle } from '../../hooks/useExpanderToggle';
+import ParamSharpness from '../../../parameters/components/Upscale/ParamSharpness';
+import ParamCreativity from '../../../parameters/components/Upscale/ParamCreativity';
+import ParamStructure from '../../../parameters/components/Upscale/ParamStructure';
+import { selectUpscalelice } from '../../../parameters/store/upscaleSlice';
+import { createMemoizedSelector } from '../../../../app/store/createMemoizedSelector';
+import { useAppSelector } from '../../../../app/store/storeHooks';
+
+const selector = createMemoizedSelector([selectUpscalelice], (upscale) => {
+ const badges: string[] = [];
+
+ if (upscale.upscaleModel) {
+ badges.push(upscale.upscaleModel.name);
+ }
+
+ return { badges };
+});
export const UpscaleSettingsAccordion = memo(() => {
const { t } = useTranslation();
+ const { badges } = useAppSelector(selector);
const { isOpen: isOpenAccordion, onToggle: onToggleAccordion } = useStandaloneAccordionToggle({
id: 'upscale-settings',
defaultIsOpen: true,
});
+ const { isOpen: isOpenExpander, onToggle: onToggleExpander } = useExpanderToggle({
+ id: 'upscale-settings-advanced',
+ defaultIsOpen: false,
+ });
+
return (
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
);
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSizeDetails.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSizeDetails.tsx
new file mode 100644
index 0000000000..2f071d77a6
--- /dev/null
+++ b/invokeai/frontend/web/src/features/settingsAccordions/components/UpscaleSettingsAccordion/UpscaleSizeDetails.tsx
@@ -0,0 +1,31 @@
+import { Flex, Text } from '@invoke-ai/ui-library';
+import { useAppSelector } from '../../../../app/store/storeHooks';
+import { useMemo } from 'react';
+
+export const UpscaleSizeDetails = () => {
+ const { upscaleInitialImage, upscaleModel } = useAppSelector((s) => s.upscale);
+
+ const scaleFactor = useMemo(() => {
+ if (upscaleModel) {
+ const upscaleFactor = upscaleModel.name.match(/x(\d+)/);
+ if (upscaleFactor && upscaleFactor[1]) {
+ return parseInt(upscaleFactor[1], 10);
+ }
+ }
+ }, [upscaleModel]);
+
+ if (!upscaleInitialImage || !upscaleModel || !scaleFactor) {
+ return <>>;
+ }
+
+ return (
+
+
+ Current image size: {upscaleInitialImage.width} x {upscaleInitialImage.height}
+
+
+ Output image size: {upscaleInitialImage.width * scaleFactor} x {upscaleInitialImage.height * scaleFactor}
+
+
+ );
+};
diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelUpscale.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelUpscale.tsx
index e6ae29cb69..44d99b3abd 100644
--- a/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelUpscale.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/ParametersPanels/ParametersPanelUpscale.tsx
@@ -1,4 +1,4 @@
-import { Box, Flex, Switch } from '@invoke-ai/ui-library';
+import { Box, Divider, Flex } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
import { Prompts } from 'features/parameters/components/Prompts/Prompts';
@@ -29,8 +29,8 @@ const ParametersPanelUpscale = () => {
-
{isSDXL ? : }
+