mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into logging-facelift
This commit is contained in:
commit
c4681774a5
@ -113,6 +113,7 @@ SAMPLER_CHOICES = [
|
||||
"lms",
|
||||
"pndm",
|
||||
"heun",
|
||||
"heun_k",
|
||||
"euler",
|
||||
"euler_k",
|
||||
"euler_a",
|
||||
|
@ -9,7 +9,8 @@ SCHEDULER_MAP = dict(
|
||||
deis=(DEISMultistepScheduler, dict()),
|
||||
lms=(LMSDiscreteScheduler, dict()),
|
||||
pndm=(PNDMScheduler, dict()),
|
||||
heun=(HeunDiscreteScheduler, dict()),
|
||||
heun=(HeunDiscreteScheduler, dict(use_karras_sigmas=False)),
|
||||
heun_k=(HeunDiscreteScheduler, dict(use_karras_sigmas=True)),
|
||||
euler=(EulerDiscreteScheduler, dict(use_karras_sigmas=False)),
|
||||
euler_k=(EulerDiscreteScheduler, dict(use_karras_sigmas=True)),
|
||||
euler_a=(EulerAncestralDiscreteScheduler, dict()),
|
||||
|
@ -9,6 +9,7 @@ SAMPLER_CHOICES = [
|
||||
"lms",
|
||||
"pndm",
|
||||
"heun",
|
||||
'heun_k',
|
||||
"euler",
|
||||
"euler_k",
|
||||
"euler_a",
|
||||
|
@ -62,11 +62,13 @@
|
||||
"@dagrejs/graphlib": "^2.1.12",
|
||||
"@emotion/react": "^11.10.6",
|
||||
"@emotion/styled": "^11.10.6",
|
||||
"@floating-ui/react-dom": "^2.0.0",
|
||||
"@fontsource/inter": "^4.5.15",
|
||||
"@reduxjs/toolkit": "^1.9.5",
|
||||
"@roarr/browser-log-writer": "^1.1.5",
|
||||
"chakra-ui-contextmenu": "^1.0.5",
|
||||
"dateformat": "^5.0.3",
|
||||
"downshift": "^7.6.0",
|
||||
"formik": "^2.2.9",
|
||||
"framer-motion": "^10.12.4",
|
||||
"fuse.js": "^6.6.2",
|
||||
|
@ -540,7 +540,10 @@
|
||||
"consoleLogLevel": "Log Level",
|
||||
"shouldLogToConsole": "Console Logging",
|
||||
"developer": "Developer",
|
||||
"general": "General"
|
||||
"general": "General",
|
||||
"generation": "Generation",
|
||||
"ui": "User Interface",
|
||||
"availableSchedulers": "Available Schedulers"
|
||||
},
|
||||
"toast": {
|
||||
"serverError": "Server Error",
|
||||
|
@ -30,9 +30,14 @@ const DEFAULT_CONFIG = {};
|
||||
interface Props {
|
||||
config?: PartialAppConfig;
|
||||
headerComponent?: ReactNode;
|
||||
setIsReady?: (isReady: boolean) => void;
|
||||
}
|
||||
|
||||
const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => {
|
||||
const App = ({
|
||||
config = DEFAULT_CONFIG,
|
||||
headerComponent,
|
||||
setIsReady,
|
||||
}: Props) => {
|
||||
useToastWatcher();
|
||||
useGlobalHotkeys();
|
||||
|
||||
@ -61,6 +66,16 @@ const App = ({ config = DEFAULT_CONFIG, headerComponent }: Props) => {
|
||||
setLoadingOverridden(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isApplicationReady && setIsReady) {
|
||||
setIsReady(true);
|
||||
}
|
||||
|
||||
return () => {
|
||||
setIsReady && setIsReady(false);
|
||||
};
|
||||
}, [isApplicationReady, setIsReady]);
|
||||
|
||||
return (
|
||||
<Grid w="100vw" h="100vh" position="relative" overflow="hidden">
|
||||
{isLightboxEnabled && <Lightbox />}
|
||||
|
@ -24,9 +24,16 @@ interface Props extends PropsWithChildren {
|
||||
token?: string;
|
||||
config?: PartialAppConfig;
|
||||
headerComponent?: ReactNode;
|
||||
setIsReady?: (isReady: boolean) => void;
|
||||
}
|
||||
|
||||
const InvokeAIUI = ({ apiUrl, token, config, headerComponent }: Props) => {
|
||||
const InvokeAIUI = ({
|
||||
apiUrl,
|
||||
token,
|
||||
config,
|
||||
headerComponent,
|
||||
setIsReady,
|
||||
}: Props) => {
|
||||
useEffect(() => {
|
||||
// configure API client token
|
||||
if (token) {
|
||||
@ -55,7 +62,11 @@ const InvokeAIUI = ({ apiUrl, token, config, headerComponent }: Props) => {
|
||||
<Provider store={store}>
|
||||
<React.Suspense fallback={<Loading />}>
|
||||
<ThemeLocaleProvider>
|
||||
<App config={config} headerComponent={headerComponent} />
|
||||
<App
|
||||
config={config}
|
||||
headerComponent={headerComponent}
|
||||
setIsReady={setIsReady}
|
||||
/>
|
||||
</ThemeLocaleProvider>
|
||||
</React.Suspense>
|
||||
</Provider>
|
||||
|
@ -1,29 +1,24 @@
|
||||
// TODO: use Enums?
|
||||
|
||||
export const DIFFUSERS_SCHEDULERS: Array<string> = [
|
||||
export const SCHEDULERS: Array<string> = [
|
||||
'ddim',
|
||||
'ddpm',
|
||||
'deis',
|
||||
'lms',
|
||||
'pndm',
|
||||
'heun',
|
||||
'euler',
|
||||
'euler_k',
|
||||
'euler_a',
|
||||
'kdpm_2',
|
||||
'kdpm_2_a',
|
||||
'dpmpp_2s',
|
||||
'dpmpp_2m',
|
||||
'dpmpp_2m_k',
|
||||
'kdpm_2',
|
||||
'kdpm_2_a',
|
||||
'deis',
|
||||
'ddpm',
|
||||
'pndm',
|
||||
'heun',
|
||||
'heun_k',
|
||||
'unipc',
|
||||
];
|
||||
|
||||
export const IMG2IMG_DIFFUSERS_SCHEDULERS = DIFFUSERS_SCHEDULERS.filter(
|
||||
(scheduler) => {
|
||||
return scheduler !== 'dpmpp_2s';
|
||||
}
|
||||
);
|
||||
|
||||
// Valid image widths
|
||||
export const WIDTHS: Array<number> = Array.from(Array(64)).map(
|
||||
(_x, i) => (i + 1) * 64
|
||||
|
@ -52,6 +52,7 @@ export type CommonGeneratedImageMetadata = {
|
||||
| 'lms'
|
||||
| 'pndm'
|
||||
| 'heun'
|
||||
| 'heun_k'
|
||||
| 'euler'
|
||||
| 'euler_k'
|
||||
| 'euler_a'
|
||||
|
172
invokeai/frontend/web/src/common/components/IAICustomSelect.tsx
Normal file
172
invokeai/frontend/web/src/common/components/IAICustomSelect.tsx
Normal file
@ -0,0 +1,172 @@
|
||||
import { CheckIcon } from '@chakra-ui/icons';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
FlexProps,
|
||||
FormControl,
|
||||
FormControlProps,
|
||||
FormLabel,
|
||||
Grid,
|
||||
GridItem,
|
||||
List,
|
||||
ListItem,
|
||||
Select,
|
||||
Text,
|
||||
Tooltip,
|
||||
TooltipProps,
|
||||
} from '@chakra-ui/react';
|
||||
import { autoUpdate, offset, shift, useFloating } from '@floating-ui/react-dom';
|
||||
import { useSelect } from 'downshift';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
|
||||
import { memo } from 'react';
|
||||
|
||||
type IAICustomSelectProps = {
|
||||
label?: string;
|
||||
items: string[];
|
||||
selectedItem: string;
|
||||
setSelectedItem: (v: string | null | undefined) => void;
|
||||
withCheckIcon?: boolean;
|
||||
formControlProps?: FormControlProps;
|
||||
buttonProps?: FlexProps;
|
||||
tooltip?: string;
|
||||
tooltipProps?: Omit<TooltipProps, 'children'>;
|
||||
};
|
||||
|
||||
const IAICustomSelect = (props: IAICustomSelectProps) => {
|
||||
const {
|
||||
label,
|
||||
items,
|
||||
setSelectedItem,
|
||||
selectedItem,
|
||||
withCheckIcon,
|
||||
formControlProps,
|
||||
tooltip,
|
||||
buttonProps,
|
||||
tooltipProps,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
isOpen,
|
||||
getToggleButtonProps,
|
||||
getLabelProps,
|
||||
getMenuProps,
|
||||
highlightedIndex,
|
||||
getItemProps,
|
||||
} = useSelect({
|
||||
items,
|
||||
selectedItem,
|
||||
onSelectedItemChange: ({ selectedItem: newSelectedItem }) =>
|
||||
setSelectedItem(newSelectedItem),
|
||||
});
|
||||
|
||||
const { refs, floatingStyles } = useFloating<HTMLButtonElement>({
|
||||
whileElementsMounted: autoUpdate,
|
||||
middleware: [offset(4), shift({ crossAxis: true, padding: 8 })],
|
||||
});
|
||||
|
||||
return (
|
||||
<FormControl sx={{ w: 'full' }} {...formControlProps}>
|
||||
{label && (
|
||||
<FormLabel
|
||||
{...getLabelProps()}
|
||||
onClick={() => {
|
||||
refs.floating.current && refs.floating.current.focus();
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</FormLabel>
|
||||
)}
|
||||
<Tooltip label={tooltip} {...tooltipProps}>
|
||||
<Select
|
||||
{...getToggleButtonProps({ ref: refs.setReference })}
|
||||
{...buttonProps}
|
||||
as={Flex}
|
||||
sx={{
|
||||
alignItems: 'center',
|
||||
userSelect: 'none',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
<Text sx={{ fontSize: 'sm', fontWeight: 500, color: 'base.100' }}>
|
||||
{selectedItem}
|
||||
</Text>
|
||||
</Select>
|
||||
</Tooltip>
|
||||
<Box {...getMenuProps()}>
|
||||
{isOpen && (
|
||||
<List
|
||||
as={Flex}
|
||||
ref={refs.setFloating}
|
||||
sx={{
|
||||
...floatingStyles,
|
||||
width: 'max-content',
|
||||
top: 0,
|
||||
left: 0,
|
||||
flexDirection: 'column',
|
||||
zIndex: 1,
|
||||
bg: 'base.800',
|
||||
borderRadius: 'base',
|
||||
border: '1px',
|
||||
borderColor: 'base.700',
|
||||
shadow: 'dark-lg',
|
||||
py: 2,
|
||||
px: 0,
|
||||
h: 'fit-content',
|
||||
maxH: 64,
|
||||
}}
|
||||
>
|
||||
<OverlayScrollbarsComponent>
|
||||
{items.map((item, index) => (
|
||||
<ListItem
|
||||
sx={{
|
||||
bg: highlightedIndex === index ? 'base.700' : undefined,
|
||||
py: 1,
|
||||
paddingInlineStart: 3,
|
||||
paddingInlineEnd: 6,
|
||||
cursor: 'pointer',
|
||||
transitionProperty: 'common',
|
||||
transitionDuration: '0.15s',
|
||||
}}
|
||||
key={`${item}${index}`}
|
||||
{...getItemProps({ item, index })}
|
||||
>
|
||||
{withCheckIcon ? (
|
||||
<Grid gridTemplateColumns="1.25rem auto">
|
||||
<GridItem>
|
||||
{selectedItem === item && <CheckIcon boxSize={2} />}
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<Text
|
||||
sx={{
|
||||
fontSize: 'sm',
|
||||
color: 'base.100',
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
{item}
|
||||
</Text>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
) : (
|
||||
<Text
|
||||
sx={{
|
||||
fontSize: 'sm',
|
||||
color: 'base.100',
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
{item}
|
||||
</Text>
|
||||
)}
|
||||
</ListItem>
|
||||
))}
|
||||
</OverlayScrollbarsComponent>
|
||||
</List>
|
||||
)}
|
||||
</Box>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(IAICustomSelect);
|
@ -4,10 +4,10 @@ import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import { isEqual } from 'lodash-es';
|
||||
|
||||
import { MdPhoto } from 'react-icons/md';
|
||||
import { selectedImageSelector } from '../store/gallerySelectors';
|
||||
import CurrentImageButtons from './CurrentImageButtons';
|
||||
import CurrentImagePreview from './CurrentImagePreview';
|
||||
import { FaImage } from 'react-icons/fa';
|
||||
|
||||
export const currentImageDisplaySelector = createSelector(
|
||||
[systemSelector, selectedImageSelector],
|
||||
@ -61,7 +61,7 @@ const CurrentImageDisplay = () => {
|
||||
</>
|
||||
) : (
|
||||
<Icon
|
||||
as={MdPhoto}
|
||||
as={FaImage}
|
||||
sx={{
|
||||
boxSize: 24,
|
||||
color: 'base.500',
|
||||
|
@ -1,9 +1,6 @@
|
||||
import {
|
||||
DIFFUSERS_SCHEDULERS,
|
||||
IMG2IMG_DIFFUSERS_SCHEDULERS,
|
||||
} from 'app/constants';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAICustomSelect from 'common/components/IAICustomSelect';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import { setSampler } from 'features/parameters/store/generationSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
@ -17,25 +14,36 @@ const ParamSampler = () => {
|
||||
|
||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
||||
|
||||
const schedulers = useAppSelector((state: RootState) => state.ui.schedulers);
|
||||
|
||||
const img2imgSchedulers = schedulers.filter((scheduler) => {
|
||||
return !['dpmpp_2s'].includes(scheduler);
|
||||
});
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChange = useCallback(
|
||||
(e: ChangeEvent<HTMLSelectElement>) => dispatch(setSampler(e.target.value)),
|
||||
(v: string | null | undefined) => {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
dispatch(setSampler(v));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return (
|
||||
<IAISelect
|
||||
<IAICustomSelect
|
||||
label={t('parameters.sampler')}
|
||||
value={sampler}
|
||||
onChange={handleChange}
|
||||
validValues={
|
||||
activeTabName === 'img2img' || activeTabName == 'unifiedCanvas'
|
||||
? IMG2IMG_DIFFUSERS_SCHEDULERS
|
||||
: DIFFUSERS_SCHEDULERS
|
||||
selectedItem={sampler}
|
||||
setSelectedItem={handleChange}
|
||||
items={
|
||||
['img2img', 'unifiedCanvas'].includes(activeTabName)
|
||||
? img2imgSchedulers
|
||||
: schedulers
|
||||
}
|
||||
minWidth={36}
|
||||
withCheckIcon
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,19 @@
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { memo } from 'react';
|
||||
import ParamSampler from './ParamSampler';
|
||||
import ModelSelect from 'features/system/components/ModelSelect';
|
||||
|
||||
const ParamSchedulerAndModel = () => {
|
||||
return (
|
||||
<Flex gap={3} w="full">
|
||||
<Box w="16rem">
|
||||
<ParamSampler />
|
||||
</Box>
|
||||
<Box w="full">
|
||||
<ModelSelect />
|
||||
</Box>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ParamSchedulerAndModel);
|
@ -1,4 +1,4 @@
|
||||
import { Flex, Image } from '@chakra-ui/react';
|
||||
import { Flex, Icon, Image } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import SelectImagePlaceholder from 'common/components/SelectImagePlaceholder';
|
||||
@ -13,6 +13,7 @@ import { generationSelector } from 'features/parameters/store/generationSelector
|
||||
import { initialImageSelected } from 'features/parameters/store/actions';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import ImageFallbackSpinner from 'features/gallery/components/ImageFallbackSpinner';
|
||||
import { FaImage } from 'react-icons/fa';
|
||||
|
||||
const selector = createSelector(
|
||||
[generationSelector],
|
||||
@ -83,7 +84,15 @@ const InitialImagePreview = () => {
|
||||
<ImageMetadataOverlay image={initialImage} />
|
||||
</>
|
||||
)}
|
||||
{!initialImage?.url && <SelectImagePlaceholder />}
|
||||
{!initialImage?.url && (
|
||||
<Icon
|
||||
as={FaImage}
|
||||
sx={{
|
||||
boxSize: 24,
|
||||
color: 'base.500',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -2,8 +2,9 @@ import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import * as InvokeAI from 'app/types/invokeai';
|
||||
import promptToString from 'common/util/promptToString';
|
||||
import { clamp } from 'lodash-es';
|
||||
import { clamp, sample } from 'lodash-es';
|
||||
import { setAllParametersReducer } from './setAllParametersReducer';
|
||||
import { receivedModels } from 'services/thunks/model';
|
||||
|
||||
export interface GenerationState {
|
||||
cfgScale: number;
|
||||
@ -236,6 +237,16 @@ export const generationSlice = createSlice({
|
||||
state.model = action.payload;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(receivedModels.fulfilled, (state, action) => {
|
||||
if (!state.model) {
|
||||
const randomModel = sample(action.payload);
|
||||
if (randomModel) {
|
||||
state.model = randomModel.name;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
|
@ -17,8 +17,17 @@ const InvokeAILogoComponent = () => {
|
||||
h="32px"
|
||||
minW="32px"
|
||||
minH="32px"
|
||||
userSelect="none"
|
||||
/>
|
||||
<Flex gap={3} display={{ base: 'inherit', sm: 'none', md: 'inherit' }}>
|
||||
<Flex
|
||||
gap={3}
|
||||
display={{
|
||||
base: 'inherit',
|
||||
sm: 'none',
|
||||
md: 'inherit',
|
||||
userSelect = 'none',
|
||||
}}
|
||||
>
|
||||
<Text fontSize="xl">
|
||||
invoke <strong>ai</strong>
|
||||
</Text>
|
||||
|
@ -1,21 +1,20 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { ChangeEvent, memo } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import { selectModelsById, selectModelsIds } from '../store/modelSlice';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { modelSelected } from 'features/parameters/store/generationSlice';
|
||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
||||
import IAICustomSelect from 'common/components/IAICustomSelect';
|
||||
|
||||
const selector = createSelector(
|
||||
[(state: RootState) => state, generationSelector],
|
||||
(state, generation) => {
|
||||
// const selectedModel = selectedModelSelector(state);
|
||||
const selectedModel = selectModelsById(state, generation.model);
|
||||
const allModelNames = selectModelsIds(state);
|
||||
const allModelNames = selectModelsIds(state).map((id) => String(id));
|
||||
return {
|
||||
allModelNames,
|
||||
selectedModel,
|
||||
@ -32,19 +31,25 @@ const ModelSelect = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const { allModelNames, selectedModel } = useAppSelector(selector);
|
||||
const handleChangeModel = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
dispatch(modelSelected(e.target.value));
|
||||
};
|
||||
const handleChangeModel = useCallback(
|
||||
(v: string | null | undefined) => {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
dispatch(modelSelected(v));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return (
|
||||
<IAISelect
|
||||
<IAICustomSelect
|
||||
label={t('modelManager.model')}
|
||||
style={{ fontSize: 'sm' }}
|
||||
aria-label={t('accessibility.modelSelect')}
|
||||
tooltip={selectedModel?.description || ''}
|
||||
value={selectedModel?.name || undefined}
|
||||
validValues={allModelNames}
|
||||
onChange={handleChangeModel}
|
||||
tooltip={selectedModel?.description}
|
||||
items={allModelNames}
|
||||
selectedItem={selectedModel?.name ?? ''}
|
||||
setSelectedItem={handleChangeModel}
|
||||
withCheckIcon={true}
|
||||
tooltipProps={{ placement: 'top', hasArrow: true }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -40,6 +40,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { VALID_LOG_LEVELS } from 'app/logging/useLogger';
|
||||
import { LogLevelName } from 'roarr';
|
||||
import { LOCALSTORAGE_KEYS, LOCALSTORAGE_PREFIX } from 'app/store/constants';
|
||||
import SettingsSchedulers from './SettingsSchedulers';
|
||||
|
||||
const selector = createSelector(
|
||||
[systemSelector, uiSelector],
|
||||
@ -171,7 +172,6 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
<Flex sx={{ gap: 4, flexDirection: 'column' }}>
|
||||
<Flex sx={modalSectionStyles}>
|
||||
<Heading size="sm">{t('settings.general')}</Heading>
|
||||
|
||||
<IAISwitch
|
||||
label={t('settings.confirmOnDelete')}
|
||||
isChecked={shouldConfirmOnDelete}
|
||||
@ -179,6 +179,15 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
dispatch(setShouldConfirmOnDelete(e.target.checked))
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
<Flex sx={modalSectionStyles}>
|
||||
<Heading size="sm">{t('settings.generation')}</Heading>
|
||||
<SettingsSchedulers />
|
||||
</Flex>
|
||||
|
||||
<Flex sx={modalSectionStyles}>
|
||||
<Heading size="sm">{t('settings.ui')}</Heading>
|
||||
<IAISwitch
|
||||
label={t('settings.displayHelpIcons')}
|
||||
isChecked={shouldDisplayGuides}
|
||||
|
@ -0,0 +1,49 @@
|
||||
import {
|
||||
Box,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItemOption,
|
||||
MenuList,
|
||||
MenuOptionGroup,
|
||||
} from '@chakra-ui/react';
|
||||
import { SCHEDULERS } from 'app/constants';
|
||||
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import { setSchedulers } from 'features/ui/store/uiSlice';
|
||||
import { isArray } from 'lodash-es';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function SettingsSchedulers() {
|
||||
const schedulers = useAppSelector((state: RootState) => state.ui.schedulers);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const schedulerSettingsHandler = (v: string | string[]) => {
|
||||
if (isArray(v)) dispatch(setSchedulers(v.sort()));
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu closeOnSelect={false}>
|
||||
<MenuButton as={IAIButton}>
|
||||
{t('settings.availableSchedulers')}
|
||||
</MenuButton>
|
||||
<MenuList maxHeight={64} overflowY="scroll">
|
||||
<MenuOptionGroup
|
||||
value={schedulers}
|
||||
type="checkbox"
|
||||
onChange={schedulerSettingsHandler}
|
||||
>
|
||||
{SCHEDULERS.map((scheduler) => (
|
||||
<MenuItemOption key={scheduler} value={scheduler}>
|
||||
{scheduler}
|
||||
</MenuItemOption>
|
||||
))}
|
||||
</MenuOptionGroup>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { memo } from 'react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
@ -9,11 +9,10 @@ import ParamSteps from 'features/parameters/components/Parameters/Core/ParamStep
|
||||
import ParamCFGScale from 'features/parameters/components/Parameters/Core/ParamCFGScale';
|
||||
import ParamWidth from 'features/parameters/components/Parameters/Core/ParamWidth';
|
||||
import ParamHeight from 'features/parameters/components/Parameters/Core/ParamHeight';
|
||||
import ParamSampler from 'features/parameters/components/Parameters/Core/ParamSampler';
|
||||
import ModelSelect from 'features/system/components/ModelSelect';
|
||||
import ImageToImageStrength from 'features/parameters/components/Parameters/ImageToImage/ImageToImageStrength';
|
||||
import ImageToImageFit from 'features/parameters/components/Parameters/ImageToImage/ImageToImageFit';
|
||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
||||
import ParamSchedulerAndModel from 'features/parameters/components/Parameters/Core/ParamSchedulerAndModel';
|
||||
|
||||
const selector = createSelector(
|
||||
[uiSelector, generationSelector],
|
||||
@ -48,14 +47,7 @@ const ImageToImageTabCoreParameters = () => {
|
||||
<ParamHeight isDisabled={!shouldFitToWidthHeight} />
|
||||
<ImageToImageStrength />
|
||||
<ImageToImageFit />
|
||||
<Flex gap={3} w="full">
|
||||
<Box flexGrow={2}>
|
||||
<ParamSampler />
|
||||
</Box>
|
||||
<Box flexGrow={3}>
|
||||
<ModelSelect />
|
||||
</Box>
|
||||
</Flex>
|
||||
<ParamSchedulerAndModel />
|
||||
</Flex>
|
||||
) : (
|
||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
||||
@ -64,14 +56,7 @@ const ImageToImageTabCoreParameters = () => {
|
||||
<ParamSteps />
|
||||
<ParamCFGScale />
|
||||
</Flex>
|
||||
<Flex gap={3} w="full">
|
||||
<Box flexGrow={2}>
|
||||
<ParamSampler />
|
||||
</Box>
|
||||
<Box flexGrow={3}>
|
||||
<ModelSelect />
|
||||
</Box>
|
||||
</Flex>
|
||||
<ParamSchedulerAndModel />
|
||||
<ParamWidth isDisabled={!shouldFitToWidthHeight} />
|
||||
<ParamHeight isDisabled={!shouldFitToWidthHeight} />
|
||||
<ImageToImageStrength />
|
||||
|
@ -3,14 +3,13 @@ import ParamSteps from 'features/parameters/components/Parameters/Core/ParamStep
|
||||
import ParamCFGScale from 'features/parameters/components/Parameters/Core/ParamCFGScale';
|
||||
import ParamWidth from 'features/parameters/components/Parameters/Core/ParamWidth';
|
||||
import ParamHeight from 'features/parameters/components/Parameters/Core/ParamHeight';
|
||||
import ParamSampler from 'features/parameters/components/Parameters/Core/ParamSampler';
|
||||
import ModelSelect from 'features/system/components/ModelSelect';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { memo } from 'react';
|
||||
import ParamSchedulerAndModel from 'features/parameters/components/Parameters/Core/ParamSchedulerAndModel';
|
||||
|
||||
const selector = createSelector(
|
||||
uiSelector,
|
||||
@ -42,14 +41,7 @@ const TextToImageTabCoreParameters = () => {
|
||||
<ParamCFGScale />
|
||||
<ParamWidth />
|
||||
<ParamHeight />
|
||||
<Flex gap={3} w="full">
|
||||
<Box flexGrow={2}>
|
||||
<ParamSampler />
|
||||
</Box>
|
||||
<Box flexGrow={3}>
|
||||
<ModelSelect />
|
||||
</Box>
|
||||
</Flex>
|
||||
<ParamSchedulerAndModel />
|
||||
</Flex>
|
||||
) : (
|
||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
||||
@ -58,14 +50,7 @@ const TextToImageTabCoreParameters = () => {
|
||||
<ParamSteps />
|
||||
<ParamCFGScale />
|
||||
</Flex>
|
||||
<Flex gap={3} w="full">
|
||||
<Box flexGrow={2}>
|
||||
<ParamSampler />
|
||||
</Box>
|
||||
<Box flexGrow={3}>
|
||||
<ModelSelect />
|
||||
</Box>
|
||||
</Flex>
|
||||
<ParamSchedulerAndModel />
|
||||
<ParamWidth />
|
||||
<ParamHeight />
|
||||
</Flex>
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { memo } from 'react';
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import ModelSelect from 'features/system/components/ModelSelect';
|
||||
import ParamIterations from 'features/parameters/components/Parameters/Core/ParamIterations';
|
||||
import ParamSteps from 'features/parameters/components/Parameters/Core/ParamSteps';
|
||||
import ParamCFGScale from 'features/parameters/components/Parameters/Core/ParamCFGScale';
|
||||
@ -12,7 +11,7 @@ import ParamWidth from 'features/parameters/components/Parameters/Core/ParamWidt
|
||||
import ParamHeight from 'features/parameters/components/Parameters/Core/ParamHeight';
|
||||
import ImageToImageStrength from 'features/parameters/components/Parameters/ImageToImage/ImageToImageStrength';
|
||||
import ImageToImageFit from 'features/parameters/components/Parameters/ImageToImage/ImageToImageFit';
|
||||
import ParamSampler from 'features/parameters/components/Parameters/Core/ParamSampler';
|
||||
import ParamSchedulerAndModel from 'features/parameters/components/Parameters/Core/ParamSchedulerAndModel';
|
||||
|
||||
const selector = createSelector(
|
||||
uiSelector,
|
||||
@ -46,14 +45,7 @@ const UnifiedCanvasCoreParameters = () => {
|
||||
<ParamHeight />
|
||||
<ImageToImageStrength />
|
||||
<ImageToImageFit />
|
||||
<Flex gap={3} w="full">
|
||||
<Box flexGrow={2}>
|
||||
<ParamSampler />
|
||||
</Box>
|
||||
<Box flexGrow={3}>
|
||||
<ModelSelect />
|
||||
</Box>
|
||||
</Flex>
|
||||
<ParamSchedulerAndModel />
|
||||
</Flex>
|
||||
) : (
|
||||
<Flex sx={{ gap: 2, flexDirection: 'column' }}>
|
||||
@ -62,14 +54,7 @@ const UnifiedCanvasCoreParameters = () => {
|
||||
<ParamSteps />
|
||||
<ParamCFGScale />
|
||||
</Flex>
|
||||
<Flex gap={3} w="full">
|
||||
<Box flexGrow={2}>
|
||||
<ParamSampler />
|
||||
</Box>
|
||||
<Box flexGrow={3}>
|
||||
<ModelSelect />
|
||||
</Box>
|
||||
</Flex>
|
||||
<ParamSchedulerAndModel />
|
||||
<ParamWidth />
|
||||
<ParamHeight />
|
||||
<ImageToImageStrength />
|
||||
|
@ -5,6 +5,7 @@ import { InvokeTabName, tabMap } from './tabMap';
|
||||
import { AddNewModelType, Coordinates, Rect, UIState } from './uiTypes';
|
||||
import { initialImageSelected } from 'features/parameters/store/actions';
|
||||
import { initialImageChanged } from 'features/parameters/store/generationSlice';
|
||||
import { SCHEDULERS } from 'app/constants';
|
||||
|
||||
export const initialUIState: UIState = {
|
||||
activeTab: 0,
|
||||
@ -27,6 +28,7 @@ export const initialUIState: UIState = {
|
||||
shouldShowProgressImages: false,
|
||||
shouldShowProgressInViewer: false,
|
||||
shouldShowImageParameters: false,
|
||||
schedulers: SCHEDULERS,
|
||||
};
|
||||
|
||||
export const uiSlice = createSlice({
|
||||
@ -146,6 +148,10 @@ export const uiSlice = createSlice({
|
||||
) => {
|
||||
state.shouldShowImageParameters = action.payload;
|
||||
},
|
||||
setSchedulers: (state, action: PayloadAction<string[]>) => {
|
||||
state.schedulers = [];
|
||||
state.schedulers = action.payload;
|
||||
},
|
||||
},
|
||||
extraReducers(builder) {
|
||||
builder.addCase(initialImageChanged, (state) => {
|
||||
@ -179,6 +185,7 @@ export const {
|
||||
setShouldShowProgressImages,
|
||||
setShouldShowProgressInViewer,
|
||||
shouldShowImageParametersChanged,
|
||||
setSchedulers,
|
||||
} = uiSlice.actions;
|
||||
|
||||
export default uiSlice.reducer;
|
||||
|
@ -33,4 +33,5 @@ export interface UIState {
|
||||
shouldShowProgressImages: boolean;
|
||||
shouldShowProgressInViewer: boolean;
|
||||
shouldShowImageParameters: boolean;
|
||||
schedulers: string[];
|
||||
}
|
||||
|
@ -57,7 +57,7 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.11"
|
||||
|
||||
"@babel/runtime@^7.1.2":
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.14.8":
|
||||
version "7.21.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200"
|
||||
integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==
|
||||
@ -1198,6 +1198,25 @@
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.39.0.tgz#58b536bcc843f4cd1e02a7e6171da5c040f4d44b"
|
||||
integrity sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==
|
||||
|
||||
"@floating-ui/core@^1.2.6":
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.6.tgz#d21ace437cc919cdd8f1640302fa8851e65e75c0"
|
||||
integrity sha512-EvYTiXet5XqweYGClEmpu3BoxmsQ4hkj3QaYA6qEnigCWffTP3vNRwBReTdrwDwo7OoJ3wM8Uoe9Uk4n+d4hfg==
|
||||
|
||||
"@floating-ui/dom@^1.2.7":
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.7.tgz#c123e4db014b07b97e996cd459245fa217049c6b"
|
||||
integrity sha512-DyqylONj1ZaBnzj+uBnVfzdjjCkFCL2aA9ESHLyUOGSqb03RpbLMImP1ekIQXYs4KLk9jAjJfZAU8hXfWSahEg==
|
||||
dependencies:
|
||||
"@floating-ui/core" "^1.2.6"
|
||||
|
||||
"@floating-ui/react-dom@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.0.tgz#7514baac526c818892bbcc84e1c3115008c029f9"
|
||||
integrity sha512-Ke0oU3SeuABC2C4OFu2mSAwHIP5WUiV98O9YWoHV4Q5aT6E9k06DV0Khi5uYspR8xmmBk08t8ZDcz3TR3ARkEg==
|
||||
dependencies:
|
||||
"@floating-ui/dom" "^1.2.7"
|
||||
|
||||
"@fontsource/inter@^4.5.15":
|
||||
version "4.5.15"
|
||||
resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-4.5.15.tgz#eed1873d68755d3b52d6fcfcfa3493118430a512"
|
||||
@ -2680,6 +2699,11 @@ compute-scroll-into-view@1.0.20:
|
||||
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43"
|
||||
integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
|
||||
|
||||
compute-scroll-into-view@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-2.0.4.tgz#2b444b2b9e4724819d2531efacb7ac094155fdf6"
|
||||
integrity sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
@ -3131,6 +3155,17 @@ dot-prop@^5.2.0:
|
||||
dependencies:
|
||||
is-obj "^2.0.0"
|
||||
|
||||
downshift@^7.6.0:
|
||||
version "7.6.0"
|
||||
resolved "https://registry.yarnpkg.com/downshift/-/downshift-7.6.0.tgz#de04fb2962bd6c4ea94589c797c91f34aa9816f3"
|
||||
integrity sha512-VSoTVynTAsabou/hbZ6HJHUVhtBiVOjQoBsCPcQq5eAROIGP+9XKMp9asAKQ3cEcUP4oe0fFdD2pziUjhFY33Q==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.8"
|
||||
compute-scroll-into-view "^2.0.4"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^17.0.2"
|
||||
tslib "^2.3.0"
|
||||
|
||||
duplexer3@^0.1.4:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e"
|
||||
@ -5356,7 +5391,7 @@ pretty-ms@^7.0.1:
|
||||
dependencies:
|
||||
parse-ms "^2.1.0"
|
||||
|
||||
prop-types@^15.6.2, prop-types@^15.8.1:
|
||||
prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@ -5517,6 +5552,11 @@ react-is@^16.13.1, react-is@^16.7.0:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-is@^17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||
|
||||
react-is@^18.0.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
@ -6485,7 +6525,7 @@ tslib@^1.10.0, tslib@^1.8.1:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0:
|
||||
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
|
||||
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
|
||||
|
Loading…
Reference in New Issue
Block a user