feat(ui): update default settings for control adapters

- Split out main model defaults
- Add controlnet/t2i defaults (which includes only the preprocessor)
This commit is contained in:
psychedelicious 2024-03-08 20:22:37 +11:00 committed by Brandon
parent 1f69613f5d
commit fd457955bc
16 changed files with 273 additions and 232 deletions

View File

@ -21,6 +21,7 @@ import { makeToast } from 'features/system/util/makeToast';
import { t } from 'i18next';
import { map } from 'lodash-es';
import { modelsApi } from 'services/api/endpoints/models';
import { isNonRefinerMainModelConfig } from 'services/api/types';
export const addSetDefaultSettingsListener = (startAppListening: AppStartListening) => {
startAppListening({
@ -36,61 +37,64 @@ export const addSetDefaultSettingsListener = (startAppListening: AppStartListeni
const modelConfig = await dispatch(modelsApi.endpoints.getModelConfig.initiate(currentModel.key)).unwrap();
if (!modelConfig || !modelConfig.default_settings) {
if (!modelConfig) {
return;
}
const { vae, vae_precision, cfg_scale, cfg_rescale_multiplier, steps, scheduler } = modelConfig.default_settings;
if (isNonRefinerMainModelConfig(modelConfig) && modelConfig.default_settings) {
const { vae, vae_precision, cfg_scale, cfg_rescale_multiplier, steps, scheduler } =
modelConfig.default_settings;
if (vae) {
// we store this as "default" within default settings
// to distinguish it from no default set
if (vae === 'default') {
dispatch(vaeSelected(null));
} else {
const { data } = modelsApi.endpoints.getVaeModels.select()(state);
const vaeArray = map(data?.entities);
const validVae = vaeArray.find((model) => model.key === vae);
if (vae) {
// we store this as "default" within default settings
// to distinguish it from no default set
if (vae === 'default') {
dispatch(vaeSelected(null));
} else {
const { data } = modelsApi.endpoints.getVaeModels.select()(state);
const vaeArray = map(data?.entities);
const validVae = vaeArray.find((model) => model.key === vae);
const result = zParameterVAEModel.safeParse(validVae);
if (!result.success) {
return;
const result = zParameterVAEModel.safeParse(validVae);
if (!result.success) {
return;
}
dispatch(vaeSelected(result.data));
}
dispatch(vaeSelected(result.data));
}
}
if (vae_precision) {
if (isParameterPrecision(vae_precision)) {
dispatch(vaePrecisionChanged(vae_precision));
if (vae_precision) {
if (isParameterPrecision(vae_precision)) {
dispatch(vaePrecisionChanged(vae_precision));
}
}
}
if (cfg_scale) {
if (isParameterCFGScale(cfg_scale)) {
dispatch(setCfgScale(cfg_scale));
if (cfg_scale) {
if (isParameterCFGScale(cfg_scale)) {
dispatch(setCfgScale(cfg_scale));
}
}
}
if (cfg_rescale_multiplier) {
if (isParameterCFGRescaleMultiplier(cfg_rescale_multiplier)) {
dispatch(setCfgRescaleMultiplier(cfg_rescale_multiplier));
if (cfg_rescale_multiplier) {
if (isParameterCFGRescaleMultiplier(cfg_rescale_multiplier)) {
dispatch(setCfgRescaleMultiplier(cfg_rescale_multiplier));
}
}
}
if (steps) {
if (isParameterSteps(steps)) {
dispatch(setSteps(steps));
if (steps) {
if (isParameterSteps(steps)) {
dispatch(setSteps(steps));
}
}
}
if (scheduler) {
if (isParameterScheduler(scheduler)) {
dispatch(setScheduler(scheduler));
if (scheduler) {
if (isParameterScheduler(scheduler)) {
dispatch(setScheduler(scheduler));
}
}
}
dispatch(addToast(makeToast({ title: t('toast.parameterSet', { parameter: 'Default settings' }) })));
dispatch(addToast(makeToast({ title: t('toast.parameterSet', { parameter: 'Default settings' }) })));
}
},
});
};

View File

@ -253,23 +253,3 @@ export const CONTROLNET_PROCESSORS: ControlNetProcessorsDict = {
},
},
};
export const CONTROLNET_MODEL_DEFAULT_PROCESSORS: {
[key: string]: ControlAdapterProcessorType;
} = {
canny: 'canny_image_processor',
mlsd: 'mlsd_image_processor',
depth: 'depth_anything_image_processor',
bae: 'normalbae_image_processor',
sketch: 'pidi_image_processor',
scribble: 'lineart_image_processor',
lineart: 'lineart_image_processor',
lineart_anime: 'lineart_anime_image_processor',
softedge: 'hed_image_processor',
shuffle: 'content_shuffle_image_processor',
openpose: 'dw_openpose_image_processor',
mediapipe: 'mediapipe_face_processor',
pidi: 'pidi_image_processor',
zoe: 'zoe_depth_image_processor',
color: 'color_map_image_processor',
};

View File

@ -1,7 +1,4 @@
import type {
ControlAdapterProcessorType,
zControlAdapterProcessorType,
} from 'features/controlAdapters/store/types';
import type { ControlAdapterProcessorType, zControlAdapterProcessorType } from 'features/controlAdapters/store/types';
import type { Equals } from 'tsafe';
import { assert } from 'tsafe';
import { describe, test } from 'vitest';

View File

@ -0,0 +1,23 @@
import { skipToken } from '@reduxjs/toolkit/query';
import { isNil } from 'lodash-es';
import { useMemo } from 'react';
import { useGetModelConfigWithTypeGuard } from 'services/api/hooks/useGetModelConfigWithTypeGuard';
import { isControlNetOrT2IAdapterModelConfig } from 'services/api/types';
export const useControlNetOrT2IAdapterDefaultSettings = (modelKey?: string | null) => {
const { modelConfig, isLoading } = useGetModelConfigWithTypeGuard(
modelKey ?? skipToken,
isControlNetOrT2IAdapterModelConfig
);
const defaultSettingsDefaults = useMemo(() => {
return {
preprocessor: {
isEnabled: !isNil(modelConfig?.default_settings?.preprocessor),
value: modelConfig?.default_settings?.preprocessor || 'none',
},
};
}, [modelConfig?.default_settings]);
return { defaultSettingsDefaults, isLoading };
};

View File

@ -0,0 +1,105 @@
import { Button, Flex, Heading, Text } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useControlNetOrT2IAdapterDefaultSettings } from 'features/modelManagerV2/hooks/useControlNetOrT2IAdapterDefaultSettings';
import { DefaultPreprocessor } from 'features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/DefaultPreprocessor';
import type { FormField } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings';
import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast';
import { useCallback } from 'react';
import type { SubmitHandler } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { PiCheckBold } from 'react-icons/pi';
import { useUpdateModelMutation } from 'services/api/endpoints/models';
export type ControlNetOrT2IAdapterDefaultSettingsFormData = {
preprocessor: FormField<string>;
};
export const ControlNetOrT2IAdapterDefaultSettings = () => {
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
const { t } = useTranslation();
const dispatch = useAppDispatch();
const { defaultSettingsDefaults, isLoading: isLoadingDefaultSettings } =
useControlNetOrT2IAdapterDefaultSettings(selectedModelKey);
const [updateModel, { isLoading: isLoadingUpdateModel }] = useUpdateModelMutation();
const { handleSubmit, control, formState, reset } = useForm<ControlNetOrT2IAdapterDefaultSettingsFormData>({
defaultValues: defaultSettingsDefaults,
});
const onSubmit = useCallback<SubmitHandler<ControlNetOrT2IAdapterDefaultSettingsFormData>>(
(data) => {
if (!selectedModelKey) {
return;
}
const body = {
preprocessor: data.preprocessor.isEnabled ? data.preprocessor.value : null,
};
updateModel({
key: selectedModelKey,
body: { default_settings: body },
})
.unwrap()
.then((_) => {
dispatch(
addToast(
makeToast({
title: t('modelManager.defaultSettingsSaved'),
status: 'success',
})
)
);
reset(data);
})
.catch((error) => {
if (error) {
dispatch(
addToast(
makeToast({
title: `${error.data.detail} `,
status: 'error',
})
)
);
}
});
},
[selectedModelKey, dispatch, reset, updateModel, t]
);
if (isLoadingDefaultSettings) {
return <Text>{t('common.loading')}</Text>;
}
return (
<>
<Flex gap="4" justifyContent="space-between" w="full" pb={4}>
<Heading fontSize="md">{t('modelManager.defaultSettings')}</Heading>
<Button
size="sm"
leftIcon={<PiCheckBold />}
colorScheme="invokeYellow"
isDisabled={!formState.isDirty}
onClick={handleSubmit(onSubmit)}
type="submit"
isLoading={isLoadingUpdateModel}
>
{t('common.save')}
</Button>
</Flex>
<Flex flexDir="column" gap={8}>
<Flex gap={8}>
<Flex gap={4} w="full">
<DefaultPreprocessor control={control} name="preprocessor" />
</Flex>
</Flex>
</Flex>
</>
);
};

View File

@ -0,0 +1,66 @@
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import type { ControlNetOrT2IAdapterDefaultSettingsFormData } from 'features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings';
import type { FormField } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/MainModelDefaultSettings';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
import { useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
const OPTIONS = [
{ label: 'Canny', value: 'canny_image_processor' },
{ label: 'MLSD', value: 'mlsd_image_processor' },
{ label: 'Depth Anything', value: 'depth_anything_image_processor' },
{ label: 'Normal BAE', value: 'normalbae_image_processor' },
{ label: 'Pidi', value: 'pidi_image_processor' },
{ label: 'Lineart', value: 'lineart_image_processor' },
{ label: 'Lineart Anime', value: 'lineart_anime_image_processor' },
{ label: 'HED', value: 'hed_image_processor' },
{ label: 'Content Shuffle', value: 'content_shuffle_image_processor' },
{ label: 'DW OpenPose', value: 'dw_openpose_image_processor' },
{ label: 'MediaPipe Face', value: 'mediapipe_face_processor' },
{ label: 'ZoeDepth', value: 'zoe_depth_image_processor' },
{ label: 'Color Map', value: 'color_map_image_processor' },
{ label: 'None', value: 'none' },
] as const;
type DefaultSchedulerType = ControlNetOrT2IAdapterDefaultSettingsFormData['preprocessor'];
export function DefaultPreprocessor(props: UseControllerProps<ControlNetOrT2IAdapterDefaultSettingsFormData>) {
const { t } = useTranslation();
const { field } = useController(props);
const onChange = useCallback<ComboboxOnChange>(
(v) => {
if (!v) {
return;
}
const updatedValue = {
...(field.value as FormField<string>),
value: v.value,
};
field.onChange(updatedValue);
},
[field]
);
const value = useMemo(() => OPTIONS.find((o) => o.value === (field.value as FormField<string>).value), [field]);
const isDisabled = useMemo(() => {
return !(field.value as DefaultSchedulerType).isEnabled;
}, [field.value]);
return (
<FormControl flexDir="column" gap={2} alignItems="flex-start">
<Flex justifyContent="space-between" w="full">
<InformationalPopover feature="controlNetProcessor">
<FormLabel>{t('controlnet.processor')}</FormLabel>
</InformationalPopover>
<SettingToggle control={props.control} name="preprocessor" />
</Flex>
<Combobox isDisabled={isDisabled} value={value} options={OPTIONS} onChange={onChange} />
</FormControl>
);
}

View File

@ -1,17 +1,17 @@
import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
import { useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import type { DefaultSettingsFormData } from './DefaultSettingsForm';
import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings';
type DefaultCfgRescaleMultiplierType = DefaultSettingsFormData['cfgRescaleMultiplier'];
type DefaultCfgRescaleMultiplierType = MainModelDefaultSettingsFormData['cfgRescaleMultiplier'];
export function DefaultCfgRescaleMultiplier(props: UseControllerProps<DefaultSettingsFormData>) {
export function DefaultCfgRescaleMultiplier(props: UseControllerProps<MainModelDefaultSettingsFormData>) {
const { field } = useController(props);
const sliderMin = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.sliderMin);

View File

@ -1,17 +1,17 @@
import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
import { useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import type { DefaultSettingsFormData } from './DefaultSettingsForm';
import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings';
type DefaultCfgType = DefaultSettingsFormData['cfgScale'];
type DefaultCfgType = MainModelDefaultSettingsFormData['cfgScale'];
export function DefaultCfgScale(props: UseControllerProps<DefaultSettingsFormData>) {
export function DefaultCfgScale(props: UseControllerProps<MainModelDefaultSettingsFormData>) {
const { field } = useController(props);
const sliderMin = useAppSelector((s) => s.config.sd.guidance.sliderMin);

View File

@ -1,7 +1,7 @@
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
import { SCHEDULER_OPTIONS } from 'features/parameters/types/constants';
import { isParameterScheduler } from 'features/parameters/types/parameterSchemas';
import { useCallback, useMemo } from 'react';
@ -9,11 +9,11 @@ import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import type { DefaultSettingsFormData } from './DefaultSettingsForm';
import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings';
type DefaultSchedulerType = DefaultSettingsFormData['scheduler'];
type DefaultSchedulerType = MainModelDefaultSettingsFormData['scheduler'];
export function DefaultScheduler(props: UseControllerProps<DefaultSettingsFormData>) {
export function DefaultScheduler(props: UseControllerProps<MainModelDefaultSettingsFormData>) {
const { t } = useTranslation();
const { field } = useController(props);

View File

@ -1,141 +0,0 @@
import { Button, Flex, Heading } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import type { ParameterScheduler } from 'features/parameters/types/parameterSchemas';
import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast';
import { useCallback } from 'react';
import type { SubmitHandler } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { PiCheckBold } from 'react-icons/pi';
import { useUpdateModelMutation } from 'services/api/endpoints/models';
import { DefaultCfgRescaleMultiplier } from './DefaultCfgRescaleMultiplier';
import { DefaultCfgScale } from './DefaultCfgScale';
import { DefaultScheduler } from './DefaultScheduler';
import { DefaultSteps } from './DefaultSteps';
import { DefaultVae } from './DefaultVae';
import { DefaultVaePrecision } from './DefaultVaePrecision';
export interface FormField<T> {
value: T;
isEnabled: boolean;
}
export type DefaultSettingsFormData = {
vae: FormField<string>;
vaePrecision: FormField<string>;
scheduler: FormField<ParameterScheduler>;
steps: FormField<number>;
cfgScale: FormField<number>;
cfgRescaleMultiplier: FormField<number>;
};
export const DefaultSettingsForm = ({
defaultSettingsDefaults,
}: {
defaultSettingsDefaults: DefaultSettingsFormData;
}) => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
const [updateModel, { isLoading }] = useUpdateModelMutation();
const { handleSubmit, control, formState, reset } = useForm<DefaultSettingsFormData>({
defaultValues: defaultSettingsDefaults,
});
const onSubmit = useCallback<SubmitHandler<DefaultSettingsFormData>>(
(data) => {
if (!selectedModelKey) {
return;
}
const body = {
vae: data.vae.isEnabled ? data.vae.value : null,
vae_precision: data.vaePrecision.isEnabled ? data.vaePrecision.value : null,
cfg_scale: data.cfgScale.isEnabled ? data.cfgScale.value : null,
cfg_rescale_multiplier: data.cfgRescaleMultiplier.isEnabled ? data.cfgRescaleMultiplier.value : null,
steps: data.steps.isEnabled ? data.steps.value : null,
scheduler: data.scheduler.isEnabled ? data.scheduler.value : null,
};
updateModel({
key: selectedModelKey,
body: { default_settings: body },
})
.unwrap()
.then((_) => {
dispatch(
addToast(
makeToast({
title: t('modelManager.defaultSettingsSaved'),
status: 'success',
})
)
);
reset(data);
})
.catch((error) => {
if (error) {
dispatch(
addToast(
makeToast({
title: `${error.data.detail} `,
status: 'error',
})
)
);
}
});
},
[selectedModelKey, dispatch, reset, updateModel, t]
);
return (
<>
<Flex gap="4" justifyContent="space-between" w="full" pb={4}>
<Heading fontSize="md">{t('modelManager.defaultSettings')}</Heading>
<Button
size="sm"
leftIcon={<PiCheckBold />}
colorScheme="invokeYellow"
isDisabled={!formState.isDirty}
onClick={handleSubmit(onSubmit)}
type="submit"
isLoading={isLoading}
>
{t('common.save')}
</Button>
</Flex>
<Flex flexDir="column" gap={8}>
<Flex gap={8}>
<Flex gap={4} w="full">
<DefaultVae control={control} name="vae" />
</Flex>
<Flex gap={4} w="full">
<DefaultVaePrecision control={control} name="vaePrecision" />
</Flex>
</Flex>
<Flex gap={8}>
<Flex gap={4} w="full">
<DefaultScheduler control={control} name="scheduler" />
</Flex>
<Flex gap={4} w="full">
<DefaultSteps control={control} name="steps" />
</Flex>
</Flex>
<Flex gap={8}>
<Flex gap={4} w="full">
<DefaultCfgScale control={control} name="cfgScale" />
</Flex>
<Flex gap={4} w="full">
<DefaultCfgRescaleMultiplier control={control} name="cfgRescaleMultiplier" />
</Flex>
</Flex>
</Flex>
</>
);
};

View File

@ -1,17 +1,17 @@
import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
import { useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import type { DefaultSettingsFormData } from './DefaultSettingsForm';
import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings';
type DefaultSteps = DefaultSettingsFormData['steps'];
type DefaultSteps = MainModelDefaultSettingsFormData['steps'];
export function DefaultSteps(props: UseControllerProps<DefaultSettingsFormData>) {
export function DefaultSteps(props: UseControllerProps<MainModelDefaultSettingsFormData>) {
const { field } = useController(props);
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);

View File

@ -3,7 +3,7 @@ import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { skipToken } from '@reduxjs/toolkit/query';
import { useAppSelector } from 'app/store/storeHooks';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
import { map } from 'lodash-es';
import { useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
@ -11,11 +11,11 @@ import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useGetModelConfigQuery, useGetVaeModelsQuery } from 'services/api/endpoints/models';
import type { DefaultSettingsFormData } from './DefaultSettingsForm';
import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings';
type DefaultVaeType = DefaultSettingsFormData['vae'];
type DefaultVaeType = MainModelDefaultSettingsFormData['vae'];
export function DefaultVae(props: UseControllerProps<DefaultSettingsFormData>) {
export function DefaultVae(props: UseControllerProps<MainModelDefaultSettingsFormData>) {
const { t } = useTranslation();
const { field } = useController(props);
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);

View File

@ -1,23 +1,23 @@
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/SettingToggle';
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
import { isParameterPrecision } from 'features/parameters/types/parameterSchemas';
import { useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import type { DefaultSettingsFormData } from './DefaultSettingsForm';
import type { MainModelDefaultSettingsFormData } from './MainModelDefaultSettings';
const options = [
{ label: 'FP16', value: 'fp16' },
{ label: 'FP32', value: 'fp32' },
];
type DefaultVaePrecisionType = DefaultSettingsFormData['vaePrecision'];
type DefaultVaePrecisionType = MainModelDefaultSettingsFormData['vaePrecision'];
export function DefaultVaePrecision(props: UseControllerProps<DefaultSettingsFormData>) {
export function DefaultVaePrecision(props: UseControllerProps<MainModelDefaultSettingsFormData>) {
const { t } = useTranslation();
const { field } = useController(props);

View File

@ -17,12 +17,13 @@ import { DefaultScheduler } from './DefaultScheduler';
import { DefaultSteps } from './DefaultSteps';
import { DefaultVae } from './DefaultVae';
import { DefaultVaePrecision } from './DefaultVaePrecision';
interface FormField<T> {
export interface FormField<T> {
value: T;
isEnabled: boolean;
}
type DefaultSettingsFormData = {
export type MainModelDefaultSettingsFormData = {
vae: FormField<string>;
vaePrecision: FormField<string>;
scheduler: FormField<ParameterScheduler>;
@ -41,11 +42,11 @@ export const MainModelDefaultSettings = () => {
const [updateModel, { isLoading: isLoadingUpdateModel }] = useUpdateModelMutation();
const { handleSubmit, control, formState, reset } = useForm<DefaultSettingsFormData>({
const { handleSubmit, control, formState, reset } = useForm<MainModelDefaultSettingsFormData>({
defaultValues: defaultSettingsDefaults,
});
const onSubmit = useCallback<SubmitHandler<DefaultSettingsFormData>>(
const onSubmit = useCallback<SubmitHandler<MainModelDefaultSettingsFormData>>(
(data) => {
if (!selectedModelKey) {
return;

View File

@ -1,6 +1,7 @@
import { Box, Flex, Text } from '@invoke-ai/ui-library';
import { skipToken } from '@reduxjs/toolkit/query';
import { useAppSelector } from 'app/store/storeHooks';
import { ControlNetOrT2IAdapterDefaultSettings } from 'features/modelManagerV2/subpanels/ModelPanel/ControlNetOrT2IAdapterDefaultSettings/ControlNetOrT2IAdapterDefaultSettings';
import { TriggerPhrases } from 'features/modelManagerV2/subpanels/ModelPanel/TriggerPhrases';
import { useTranslation } from 'react-i18next';
import { useGetModelConfigQuery } from 'services/api/endpoints/models';
@ -64,6 +65,11 @@ export const ModelView = () => {
<MainModelDefaultSettings />
</Box>
)}
{(data.type === 'controlnet' || data.type === 't2i_adapter') && (
<Box layerStyle="second" borderRadius="base" p={4}>
<ControlNetOrT2IAdapterDefaultSettings />
</Box>
)}
{(data.type === 'main' || data.type === 'lora') && (
<Box layerStyle="second" borderRadius="base" p={4}>
<TriggerPhrases />

View File

@ -4,9 +4,9 @@ import { useCallback, useMemo } from 'react';
import type { UseControllerProps } from 'react-hook-form';
import { useController } from 'react-hook-form';
import type { DefaultSettingsFormData, FormField } from './DefaultSettingsForm';
import type { FormField } from './MainModelDefaultSettings/MainModelDefaultSettings';
export function SettingToggle<T>(props: UseControllerProps<DefaultSettingsFormData>) {
export function SettingToggle<T, F extends Record<string, FormField<T>>>(props: UseControllerProps<F>) {
const { field } = useController(props);
const value = useMemo(() => {