mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
UI for configuring default settings for models'
This commit is contained in:
parent
5a35550144
commit
6e0665e3d7
@ -0,0 +1,119 @@
|
|||||||
|
import { Button, Flex, Heading } from '@invoke-ai/ui-library';
|
||||||
|
import { SubmitHandler, useForm } from 'react-hook-form';
|
||||||
|
import { SettingToggle } from './DefaultSettings/SettingToggle';
|
||||||
|
import { DefaultCfgScale } from './DefaultSettings/DefaultCfgScale';
|
||||||
|
import { DefaultSteps } from './DefaultSettings/DefaultSteps';
|
||||||
|
import { useAppSelector } from '../../../../app/store/storeHooks';
|
||||||
|
import { DefaultScheduler } from './DefaultSettings/DefaultScheduler';
|
||||||
|
import { selectGenerationSlice } from '../../../parameters/store/generationSlice';
|
||||||
|
import { createMemoizedSelector } from '../../../../app/store/createMemoizedSelector';
|
||||||
|
import { selectConfigSlice } from '../../../system/store/configSlice';
|
||||||
|
import { DefaultVaePrecision } from './DefaultSettings/DefaultVaePrecision';
|
||||||
|
import { DefaultCfgRescaleMultiplier } from './DefaultSettings/DefaultCfgRescaleMultiplier';
|
||||||
|
import { DefaultVae } from './DefaultSettings/DefaultVae';
|
||||||
|
import { t } from 'i18next';
|
||||||
|
import { IoPencil } from 'react-icons/io5';
|
||||||
|
import { each } from 'lodash-es';
|
||||||
|
|
||||||
|
export interface FormField<T> {
|
||||||
|
value: T;
|
||||||
|
isEnabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DefaultSettingsFormData = {
|
||||||
|
vae: FormField<string | null>;
|
||||||
|
vaePrecision: FormField<string>;
|
||||||
|
scheduler: FormField<string>;
|
||||||
|
steps: FormField<number>;
|
||||||
|
cfgScale: FormField<number>;
|
||||||
|
cfgRescaleMultiplier: FormField<number>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialStatesSelector = createMemoizedSelector(selectConfigSlice, (config) => {
|
||||||
|
const { steps, guidance, scheduler, cfgRescaleMultiplier, vaePrecision } = config.sd;
|
||||||
|
|
||||||
|
return {
|
||||||
|
initialSteps: steps.initial,
|
||||||
|
initialCfg: guidance.initial,
|
||||||
|
initialScheduler: scheduler,
|
||||||
|
initialCfgRescaleMultiplier: cfgRescaleMultiplier.initial,
|
||||||
|
initialVaePrecision: vaePrecision,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const DefaultSettings = () => {
|
||||||
|
const { initialSteps, initialCfg, initialScheduler, initialCfgRescaleMultiplier, initialVaePrecision } =
|
||||||
|
useAppSelector(initialStatesSelector);
|
||||||
|
|
||||||
|
const { handleSubmit, control, formState } = useForm<DefaultSettingsFormData>({
|
||||||
|
defaultValues: {
|
||||||
|
vae: { isEnabled: false, value: null },
|
||||||
|
vaePrecision: { isEnabled: false, value: initialVaePrecision },
|
||||||
|
scheduler: { isEnabled: false, value: initialScheduler },
|
||||||
|
steps: { isEnabled: false, value: initialSteps },
|
||||||
|
cfgScale: { isEnabled: false, value: initialCfg },
|
||||||
|
cfgRescaleMultiplier: { isEnabled: false, value: initialCfgRescaleMultiplier },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<DefaultSettingsFormData> = (data) => {
|
||||||
|
const body: { [key: string]: string | number | null } = {};
|
||||||
|
each(data, (value, key) => {
|
||||||
|
if (value.isEnabled) {
|
||||||
|
body[key] = value.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(body);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Flex gap="2" justifyContent="space-between" w="full" mb={5}>
|
||||||
|
<Heading fontSize="md">Default Settings</Heading>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
leftIcon={<IoPencil />}
|
||||||
|
colorScheme="invokeYellow"
|
||||||
|
isDisabled={!formState.isDirty}
|
||||||
|
onClick={handleSubmit(onSubmit)}
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{t('common.save')}
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex flexDir="column" gap={8}>
|
||||||
|
<Flex gap={8}>
|
||||||
|
<Flex gap={4} w="full">
|
||||||
|
<SettingToggle control={control} name="vae" />
|
||||||
|
<DefaultVae control={control} name="vae" />
|
||||||
|
</Flex>
|
||||||
|
<Flex gap={4} w="full">
|
||||||
|
<SettingToggle control={control} name="vaePrecision" />
|
||||||
|
<DefaultVaePrecision control={control} name="vaePrecision" />
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
<Flex gap={8}>
|
||||||
|
<Flex gap={4} w="full">
|
||||||
|
<SettingToggle control={control} name="scheduler" />
|
||||||
|
<DefaultScheduler control={control} name="scheduler" />
|
||||||
|
</Flex>
|
||||||
|
<Flex gap={4} w="full">
|
||||||
|
<SettingToggle control={control} name="steps" />
|
||||||
|
<DefaultSteps control={control} name="steps" />
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
<Flex gap={8}>
|
||||||
|
<Flex gap={4} w="full">
|
||||||
|
<SettingToggle control={control} name="cfgScale" />
|
||||||
|
<DefaultCfgScale control={control} name="cfgScale" />
|
||||||
|
</Flex>
|
||||||
|
<Flex gap={4} w="full">
|
||||||
|
<SettingToggle control={control} name="cfgRescaleMultiplier" />
|
||||||
|
<DefaultCfgRescaleMultiplier control={control} name="cfgRescaleMultiplier" />
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,71 @@
|
|||||||
|
import { FormControl, FormLabel, CompositeSlider, CompositeNumberInput, Flex } from '@invoke-ai/ui-library';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useAppSelector } from '../../../../../app/store/storeHooks';
|
||||||
|
import { InformationalPopover } from '../../../../../common/components/InformationalPopover/InformationalPopover';
|
||||||
|
import { UseControllerProps, useController } from 'react-hook-form';
|
||||||
|
import { DefaultSettingsFormData } from '../DefaultSettings';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
type DefaultCfgRescaleMultiplierType = DefaultSettingsFormData['cfgRescaleMultiplier'];
|
||||||
|
|
||||||
|
export function DefaultCfgRescaleMultiplier(props: UseControllerProps<DefaultSettingsFormData>) {
|
||||||
|
const { field } = useController(props);
|
||||||
|
|
||||||
|
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 { t } = useTranslation();
|
||||||
|
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
|
||||||
|
|
||||||
|
const onChange = useCallback(
|
||||||
|
(v: number) => {
|
||||||
|
const updatedValue = {
|
||||||
|
...(field.value as DefaultCfgRescaleMultiplierType),
|
||||||
|
value: v,
|
||||||
|
};
|
||||||
|
field.onChange(updatedValue);
|
||||||
|
},
|
||||||
|
[field]
|
||||||
|
);
|
||||||
|
|
||||||
|
const value = useMemo(() => {
|
||||||
|
return (field.value as DefaultCfgRescaleMultiplierType).value;
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
const isDisabled = useMemo(() => {
|
||||||
|
return !(field.value as DefaultCfgRescaleMultiplierType).isEnabled;
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl flexDir="column" gap={1} alignItems="flex-start">
|
||||||
|
<InformationalPopover feature="paramCFGRescaleMultiplier">
|
||||||
|
<FormLabel>{t('parameters.cfgRescaleMultiplier')}</FormLabel>
|
||||||
|
</InformationalPopover>
|
||||||
|
<Flex w="full" gap={1}>
|
||||||
|
<CompositeSlider
|
||||||
|
value={value}
|
||||||
|
min={sliderMin}
|
||||||
|
max={sliderMax}
|
||||||
|
step={coarseStep}
|
||||||
|
fineStep={fineStep}
|
||||||
|
onChange={onChange}
|
||||||
|
marks={marks}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
/>
|
||||||
|
<CompositeNumberInput
|
||||||
|
value={value}
|
||||||
|
min={numberInputMin}
|
||||||
|
max={numberInputMax}
|
||||||
|
step={coarseStep}
|
||||||
|
fineStep={fineStep}
|
||||||
|
onChange={onChange}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
import { FormControl, FormLabel, CompositeSlider, CompositeNumberInput, Flex } from '@invoke-ai/ui-library';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useAppSelector } from '../../../../../app/store/storeHooks';
|
||||||
|
import { InformationalPopover } from '../../../../../common/components/InformationalPopover/InformationalPopover';
|
||||||
|
import { UseControllerProps, useController } from 'react-hook-form';
|
||||||
|
import { DefaultSettingsFormData } from '../DefaultSettings';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
type DefaultCfgType = DefaultSettingsFormData['cfgScale'];
|
||||||
|
|
||||||
|
export function DefaultCfgScale(props: UseControllerProps<DefaultSettingsFormData>) {
|
||||||
|
const { field } = useController(props);
|
||||||
|
|
||||||
|
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 { t } = useTranslation();
|
||||||
|
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
|
||||||
|
|
||||||
|
const onChange = useCallback(
|
||||||
|
(v: number) => {
|
||||||
|
const updatedValue = {
|
||||||
|
...(field.value as DefaultCfgType),
|
||||||
|
value: v,
|
||||||
|
};
|
||||||
|
field.onChange(updatedValue);
|
||||||
|
},
|
||||||
|
[field]
|
||||||
|
);
|
||||||
|
|
||||||
|
const value = useMemo(() => {
|
||||||
|
return (field.value as DefaultCfgType).value;
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
const isDisabled = useMemo(() => {
|
||||||
|
return !(field.value as DefaultCfgType).isEnabled;
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl flexDir="column" gap={1} alignItems="flex-start">
|
||||||
|
<InformationalPopover feature="paramCFGScale">
|
||||||
|
<FormLabel>{t('parameters.cfgScale')}</FormLabel>
|
||||||
|
</InformationalPopover>
|
||||||
|
<Flex w="full" gap={1}>
|
||||||
|
<CompositeSlider
|
||||||
|
value={value}
|
||||||
|
min={sliderMin}
|
||||||
|
max={sliderMax}
|
||||||
|
step={coarseStep}
|
||||||
|
fineStep={fineStep}
|
||||||
|
onChange={onChange}
|
||||||
|
marks={marks}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
/>
|
||||||
|
<CompositeNumberInput
|
||||||
|
value={value}
|
||||||
|
min={numberInputMin}
|
||||||
|
max={numberInputMax}
|
||||||
|
step={coarseStep}
|
||||||
|
fineStep={fineStep}
|
||||||
|
onChange={onChange}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||||
|
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||||
|
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||||
|
import { SCHEDULER_OPTIONS } from 'features/parameters/types/constants';
|
||||||
|
import { isParameterScheduler } from 'features/parameters/types/parameterSchemas';
|
||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { DefaultSettingsFormData } from '../DefaultSettings';
|
||||||
|
import { UseControllerProps, useController } from 'react-hook-form';
|
||||||
|
|
||||||
|
type DefaultSchedulerType = DefaultSettingsFormData['scheduler'];
|
||||||
|
|
||||||
|
export function DefaultScheduler(props: UseControllerProps<DefaultSettingsFormData>) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { field } = useController(props);
|
||||||
|
|
||||||
|
const onChange = useCallback<ComboboxOnChange>(
|
||||||
|
(v) => {
|
||||||
|
if (!isParameterScheduler(v?.value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const updatedValue = {
|
||||||
|
...(field.value as DefaultSchedulerType),
|
||||||
|
value: v.value,
|
||||||
|
};
|
||||||
|
field.onChange(updatedValue);
|
||||||
|
},
|
||||||
|
[field]
|
||||||
|
);
|
||||||
|
|
||||||
|
const value = useMemo(
|
||||||
|
() => SCHEDULER_OPTIONS.find((o) => o.value === (field.value as DefaultSchedulerType).value),
|
||||||
|
[field]
|
||||||
|
);
|
||||||
|
|
||||||
|
const isDisabled = useMemo(() => {
|
||||||
|
return !(field.value as DefaultSchedulerType).isEnabled;
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl flexDir="column" gap={1} alignItems="flex-start">
|
||||||
|
<InformationalPopover feature="paramScheduler">
|
||||||
|
<FormLabel>{t('parameters.scheduler')}</FormLabel>
|
||||||
|
</InformationalPopover>
|
||||||
|
<Combobox isDisabled={isDisabled} value={value} options={SCHEDULER_OPTIONS} onChange={onChange} />
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
import { FormControl, FormLabel, CompositeSlider, CompositeNumberInput, Flex } from '@invoke-ai/ui-library';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useAppSelector } from '../../../../../app/store/storeHooks';
|
||||||
|
import { InformationalPopover } from '../../../../../common/components/InformationalPopover/InformationalPopover';
|
||||||
|
import { UseControllerProps, useController } from 'react-hook-form';
|
||||||
|
import { DefaultSettingsFormData } from '../DefaultSettings';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
type DefaultSteps = DefaultSettingsFormData['steps'];
|
||||||
|
|
||||||
|
export function DefaultSteps(props: UseControllerProps<DefaultSettingsFormData>) {
|
||||||
|
const { field } = useController(props);
|
||||||
|
|
||||||
|
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 { t } = useTranslation();
|
||||||
|
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
|
||||||
|
|
||||||
|
const onChange = useCallback(
|
||||||
|
(v: number) => {
|
||||||
|
const updatedValue = {
|
||||||
|
...(field.value as DefaultSteps),
|
||||||
|
value: v,
|
||||||
|
};
|
||||||
|
field.onChange(updatedValue);
|
||||||
|
},
|
||||||
|
[field]
|
||||||
|
);
|
||||||
|
|
||||||
|
const value = useMemo(() => {
|
||||||
|
return (field.value as DefaultSteps).value;
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
const isDisabled = useMemo(() => {
|
||||||
|
return !(field.value as DefaultSteps).isEnabled;
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl flexDir="column" gap={1} alignItems="flex-start">
|
||||||
|
<InformationalPopover feature="paramSteps">
|
||||||
|
<FormLabel>{t('parameters.steps')}</FormLabel>
|
||||||
|
</InformationalPopover>
|
||||||
|
<Flex w="full" gap={1}>
|
||||||
|
<CompositeSlider
|
||||||
|
value={value}
|
||||||
|
min={sliderMin}
|
||||||
|
max={sliderMax}
|
||||||
|
step={coarseStep}
|
||||||
|
fineStep={fineStep}
|
||||||
|
onChange={onChange}
|
||||||
|
marks={marks}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
/>
|
||||||
|
<CompositeNumberInput
|
||||||
|
value={value}
|
||||||
|
min={numberInputMin}
|
||||||
|
max={numberInputMax}
|
||||||
|
step={coarseStep}
|
||||||
|
fineStep={fineStep}
|
||||||
|
onChange={onChange}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||||
|
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||||
|
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { DefaultSettingsFormData } from '../DefaultSettings';
|
||||||
|
import { UseControllerProps, useController } from 'react-hook-form';
|
||||||
|
import { useGetModelConfigQuery, useGetVaeModelsQuery } from '../../../../../services/api/endpoints/models';
|
||||||
|
import { map } from 'lodash-es';
|
||||||
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
|
import { useAppSelector } from '../../../../../app/store/storeHooks';
|
||||||
|
|
||||||
|
type DefaultVaeType = DefaultSettingsFormData['vae'];
|
||||||
|
|
||||||
|
export function DefaultVae(props: UseControllerProps<DefaultSettingsFormData>) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { field } = useController(props);
|
||||||
|
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
|
||||||
|
const { data: modelData } = useGetModelConfigQuery(selectedModelKey ?? skipToken);
|
||||||
|
|
||||||
|
const { compatibleOptions } = useGetVaeModelsQuery(undefined, {
|
||||||
|
selectFromResult: ({ data }) => {
|
||||||
|
const modelArray = map(data?.entities);
|
||||||
|
const compatibleOptions = modelArray
|
||||||
|
.filter((vae) => vae.base === modelData?.base)
|
||||||
|
.map((vae) => ({ label: vae.name, value: vae.key }));
|
||||||
|
|
||||||
|
return { compatibleOptions };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onChange = useCallback<ComboboxOnChange>(
|
||||||
|
(v) => {
|
||||||
|
const newValue = !v?.value ? null : v.value;
|
||||||
|
|
||||||
|
const updatedValue = {
|
||||||
|
...(field.value as DefaultVaeType),
|
||||||
|
value: newValue,
|
||||||
|
};
|
||||||
|
field.onChange(updatedValue);
|
||||||
|
},
|
||||||
|
[field]
|
||||||
|
);
|
||||||
|
|
||||||
|
const value = useMemo(() => {
|
||||||
|
return compatibleOptions.find((vae) => vae.value === (field.value as DefaultVaeType).value);
|
||||||
|
}, [compatibleOptions, field.value]);
|
||||||
|
|
||||||
|
const isDisabled = useMemo(() => {
|
||||||
|
return !(field.value as DefaultVaeType).isEnabled;
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl flexDir="column" gap={1} alignItems="flex-start">
|
||||||
|
<InformationalPopover feature="paramVAE">
|
||||||
|
<FormLabel>{t('modelManager.vae')}</FormLabel>
|
||||||
|
</InformationalPopover>
|
||||||
|
<Combobox
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
isClearable
|
||||||
|
value={value}
|
||||||
|
placeholder={value ? value.value : t('models.defaultVAE')}
|
||||||
|
options={compatibleOptions}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||||
|
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||||
|
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||||
|
import { isParameterPrecision, isParameterScheduler } from 'features/parameters/types/parameterSchemas';
|
||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { DefaultSettingsFormData } from '../DefaultSettings';
|
||||||
|
import { UseControllerProps, useController } from 'react-hook-form';
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{ label: 'FP16', value: 'fp16' },
|
||||||
|
{ label: 'FP32', value: 'fp32' },
|
||||||
|
];
|
||||||
|
|
||||||
|
type DefaultVaePrecisionType = DefaultSettingsFormData['vaePrecision'];
|
||||||
|
|
||||||
|
export function DefaultVaePrecision(props: UseControllerProps<DefaultSettingsFormData>) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { field } = useController(props);
|
||||||
|
|
||||||
|
const onChange = useCallback<ComboboxOnChange>(
|
||||||
|
(v) => {
|
||||||
|
if (!isParameterPrecision(v?.value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const updatedValue = {
|
||||||
|
...(field.value as DefaultVaePrecisionType),
|
||||||
|
value: v.value,
|
||||||
|
};
|
||||||
|
field.onChange(updatedValue);
|
||||||
|
},
|
||||||
|
[field]
|
||||||
|
);
|
||||||
|
|
||||||
|
const value = useMemo(() => options.find((o) => o.value === (field.value as DefaultVaePrecisionType).value), [field]);
|
||||||
|
|
||||||
|
const isDisabled = useMemo(() => {
|
||||||
|
return !(field.value as DefaultVaePrecisionType).isEnabled;
|
||||||
|
}, [field.value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl flexDir="column" gap={1} alignItems="flex-start">
|
||||||
|
<InformationalPopover feature="paramVAEPrecision">
|
||||||
|
<FormLabel>{t('modelManager.vaePrecision')}</FormLabel>
|
||||||
|
</InformationalPopover>
|
||||||
|
<Combobox isDisabled={isDisabled} value={value} options={options} onChange={onChange} />
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
import { UseControllerProps, useController, useFormContext, useWatch } from 'react-hook-form';
|
||||||
|
import { DefaultSettingsFormData, FormField } from '../DefaultSettings';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { Switch } from '@invoke-ai/ui-library';
|
||||||
|
import { ChangeEvent } from 'react';
|
||||||
|
|
||||||
|
interface Props<T> extends UseControllerProps<DefaultSettingsFormData> {
|
||||||
|
name: keyof DefaultSettingsFormData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingToggle<T>(props: Props<T>) {
|
||||||
|
const { field } = useController(props);
|
||||||
|
|
||||||
|
const onChange = useCallback(
|
||||||
|
(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const updatedValue: FormField<T> = {
|
||||||
|
...(field.value as FormField<T>),
|
||||||
|
isEnabled: e.target.checked,
|
||||||
|
};
|
||||||
|
field.onChange(updatedValue);
|
||||||
|
},
|
||||||
|
[field]
|
||||||
|
);
|
||||||
|
|
||||||
|
return <Switch onChange={onChange} />;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, Button, Flex, Text } from '@invoke-ai/ui-library';
|
import { Box, Button, Flex, Heading, Text } from '@invoke-ai/ui-library';
|
||||||
import { skipToken } from '@reduxjs/toolkit/query';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||||
@ -19,6 +19,7 @@ import type {
|
|||||||
|
|
||||||
import { ModelAttrView } from './ModelAttrView';
|
import { ModelAttrView } from './ModelAttrView';
|
||||||
import { ModelConvert } from './ModelConvert';
|
import { ModelConvert } from './ModelConvert';
|
||||||
|
import { DefaultSettings } from './DefaultSettings';
|
||||||
|
|
||||||
export const ModelView = () => {
|
export const ModelView = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -71,7 +72,7 @@ export const ModelView = () => {
|
|||||||
return <Text>{t('common.somethingWentWrong')}</Text>;
|
return <Text>{t('common.somethingWentWrong')}</Text>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Flex flexDir="column" h="full">
|
<Flex flexDir="column" h="full" gap="2">
|
||||||
<Box layerStyle="second" borderRadius="base" p={3}>
|
<Box layerStyle="second" borderRadius="base" p={3}>
|
||||||
<Flex gap="2" justifyContent="flex-end" w="full">
|
<Flex gap="2" justifyContent="flex-end" w="full">
|
||||||
<Button size="sm" leftIcon={<IoPencil />} colorScheme="invokeYellow" onClick={handleEditModel}>
|
<Button size="sm" leftIcon={<IoPencil />} colorScheme="invokeYellow" onClick={handleEditModel}>
|
||||||
@ -118,6 +119,9 @@ export const ModelView = () => {
|
|||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Box>
|
</Box>
|
||||||
|
<Box layerStyle="second" borderRadius="base" p={3}>
|
||||||
|
<DefaultSettings />
|
||||||
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user