add model convert to checkpoint main models

This commit is contained in:
Mary Hipp 2024-02-23 16:03:36 -05:00 committed by psychedelicious
parent c3f4e87a6e
commit 9b1f63379a
9 changed files with 224 additions and 46 deletions

View File

@ -0,0 +1,32 @@
import type { ButtonProps } from '@invoke-ai/ui-library';
import { Button } from '@invoke-ai/ui-library';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiArrowsClockwiseBold } from 'react-icons/pi';
import { useSyncModels } from './useSyncModels';
export const SyncModelsButton = memo((props: Omit<ButtonProps, 'children'>) => {
const { t } = useTranslation();
const { syncModels, isLoading } = useSyncModels();
const isSyncModelEnabled = useFeatureStatus('syncModels').isFeatureEnabled;
if (!isSyncModelEnabled) {
return null;
}
return (
<Button
isLoading={isLoading}
onClick={syncModels}
leftIcon={<PiArrowsClockwiseBold />}
minW="max-content"
{...props}
>
{t('modelManager.syncModels')}
</Button>
);
});
SyncModelsButton.displayName = 'SyncModelsButton';

View File

@ -0,0 +1,33 @@
import type { IconButtonProps } from '@invoke-ai/ui-library';
import { IconButton } from '@invoke-ai/ui-library';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiArrowsClockwiseBold } from 'react-icons/pi';
import { useSyncModels } from './useSyncModels';
export const SyncModelsIconButton = memo((props: Omit<IconButtonProps, 'aria-label'>) => {
const { t } = useTranslation();
const { syncModels, isLoading } = useSyncModels();
const isSyncModelEnabled = useFeatureStatus('syncModels').isFeatureEnabled;
if (!isSyncModelEnabled) {
return null;
}
return (
<IconButton
icon={<PiArrowsClockwiseBold />}
tooltip={t('modelManager.syncModels')}
aria-label={t('modelManager.syncModels')}
isLoading={isLoading}
onClick={syncModels}
size="sm"
variant="ghost"
{...props}
/>
);
});
SyncModelsIconButton.displayName = 'SyncModelsIconButton';

View File

@ -0,0 +1,40 @@
import { useAppDispatch } from 'app/store/storeHooks';
import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useSyncModelsMutation } from 'services/api/endpoints/models';
export const useSyncModels = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const [_syncModels, { isLoading }] = useSyncModelsMutation();
const syncModels = useCallback(() => {
_syncModels()
.unwrap()
.then((_) => {
dispatch(
addToast(
makeToast({
title: `${t('modelManager.modelsSynced')}`,
status: 'success',
})
)
);
})
.catch((error) => {
if (error) {
dispatch(
addToast(
makeToast({
title: `${t('modelManager.modelSyncFailed')}`,
status: 'error',
})
)
);
}
});
}, [dispatch, _syncModels, t]);
return { syncModels, isLoading };
};

View File

@ -52,7 +52,7 @@ export const migrateModelManagerState = (state: any): any => {
return state;
};
export const modelManagerPersistConfig: PersistConfig<ModelManagerState> = {
export const modelManagerV2PersistConfig: PersistConfig<ModelManagerState> = {
name: modelManagerV2Slice.name,
initialState: initialModelManagerState,
migrate: migrateModelManagerState,

View File

@ -1,32 +0,0 @@
import type { ChakraProps, ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
import { memo, useCallback, useMemo } from 'react';
import { useController, type UseControllerProps } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useGetCheckpointConfigsQuery } from 'services/api/endpoints/models';
import type { CheckpointModelConfig } from 'services/api/types';
const sx: ChakraProps['sx'] = { w: 'full' };
const CheckpointConfigsSelect = (props: UseControllerProps<CheckpointModelConfig>) => {
const { data } = useGetCheckpointConfigsQuery();
const { t } = useTranslation();
const options = useMemo<ComboboxOption[]>(() => (data ? data.map((i) => ({ label: i, value: i })) : []), [data]);
const { field } = useController(props);
const value = useMemo(() => options.find((o) => o.value === field.value), [field.value, options]);
const onChange = useCallback<ComboboxOnChange>(
(v) => {
field.onChange(v?.value);
},
[field]
);
return (
<FormControl>
<FormLabel>{t('modelManager.configFile')}</FormLabel>
<Combobox placeholder="Select A Config File" value={value} options={options} onChange={onChange} sx={sx} />
</FormControl>
);
};
export default memo(CheckpointConfigsSelect);

View File

@ -1,6 +1,6 @@
import { Box, Button, Flex, Heading } from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
import { SyncModelsIconButton } from 'features/modelManager/components/SyncModels/SyncModelsIconButton';
import { SyncModelsIconButton } from 'features/modelManagerV2/components/SyncModels/SyncModelsIconButton';
import { setSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice';
import { useCallback } from 'react';
@ -20,12 +20,9 @@ export const ModelManager = () => {
<Heading fontSize="xl">Model Manager</Heading>
<SyncModelsIconButton />
</Flex>
<Flex gap={2}>
<Button colorScheme="invokeYellow" onClick={handleClickAddModel}>
Add Model
</Button>
<Button>Scan for Models</Button>
</Flex>
<Button colorScheme="invokeYellow" onClick={handleClickAddModel}>
Add Models
</Button>
</Flex>
<Box layerStyle="second" p={3} borderRadius="base" w="full" h="full">
<ModelListNavigation />

View File

@ -0,0 +1,104 @@
import {
Button,
ConfirmationAlertDialog,
Divider,
Flex,
ListItem,
Text,
UnorderedList,
useDisclosure,
} from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useConvertMainModelsMutation } from 'services/api/endpoints/models';
import type { CheckpointModelConfig } from 'services/api/types';
interface ModelConvertProps {
model: CheckpointModelConfig;
}
export const ModelConvert = (props: ModelConvertProps) => {
const { model } = props;
const dispatch = useAppDispatch();
const { t } = useTranslation();
const [convertModel, { isLoading }] = useConvertMainModelsMutation();
const { isOpen, onOpen, onClose } = useDisclosure();
const modelConvertHandler = useCallback(() => {
dispatch(
addToast(
makeToast({
title: `${t('modelManager.convertingModelBegin')}: ${model.name}`,
status: 'info',
})
)
);
convertModel(model.key)
.unwrap()
.then(() => {
dispatch(
addToast(
makeToast({
title: `${t('modelManager.modelConverted')}: ${model.name}`,
status: 'success',
})
)
);
})
.catch(() => {
dispatch(
addToast(
makeToast({
title: `${t('modelManager.modelConversionFailed')}: ${model.name}`,
status: 'error',
})
)
);
});
}, [convertModel, dispatch, model.base, model.name, t]);
return (
<>
<Button
onClick={onOpen}
size="sm"
aria-label={t('modelManager.convertToDiffusers')}
className=" modal-close-btn"
isLoading={isLoading}
>
🧨 {t('modelManager.convertToDiffusers')}
</Button>
<ConfirmationAlertDialog
title={`${t('modelManager.convert')} ${model.name}`}
acceptCallback={modelConvertHandler}
acceptButtonText={`${t('modelManager.convert')}`}
isOpen={isOpen}
onClose={onClose}
>
<Flex flexDirection="column" rowGap={4}>
<Text fontSize="md">{t('modelManager.convertToDiffusersHelpText1')}</Text>
<UnorderedList>
<ListItem>
<Text fontSize="md">{t('modelManager.convertToDiffusersHelpText2')}</Text>
</ListItem>
<ListItem>
<Text fontSize="md">{t('modelManager.convertToDiffusersHelpText3')}</Text>
</ListItem>
<ListItem>
<Text fontSize="md">{t('modelManager.convertToDiffusersHelpText4')}</Text>
</ListItem>
<ListItem>
<Text fontSize="md">{t('modelManager.convertToDiffusersHelpText5')}</Text>
</ListItem>
</UnorderedList>
<Divider />
<Text fontSize="md">{t('modelManager.convertToDiffusersHelpText6')}</Text>
</Flex>
</ConfirmationAlertDialog>
</>
);
};

View File

@ -171,7 +171,7 @@ export const ModelEdit = () => {
colorScheme="invokeYellow"
onClick={handleSubmit(onSubmit)}
isLoading={isSubmitting}
isDisabled={Boolean(errors)}
isDisabled={Boolean(Object.keys(errors).length)}
>
Save
</Button>

View File

@ -1,11 +1,11 @@
import { Box,Button, Flex, Heading, Text } from '@invoke-ai/ui-library';
import { Box, Button, Flex, Heading, Text } from '@invoke-ai/ui-library';
import { skipToken } from '@reduxjs/toolkit/query';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
import { useCallback, useMemo } from 'react';
import { IoPencil } from 'react-icons/io5';
import { useGetModelConfigQuery,useGetModelMetadataQuery } from 'services/api/endpoints/models';
import { useGetModelConfigQuery, useGetModelMetadataQuery } from 'services/api/endpoints/models';
import type {
CheckpointModelConfig,
ControlNetModelConfig,
@ -18,6 +18,7 @@ import type {
} from 'services/api/types';
import { ModelAttrView } from './ModelAttrView';
import { ModelConvert } from './ModelConvert';
export const ModelView = () => {
const dispatch = useAppDispatch();
@ -79,9 +80,12 @@ export const ModelView = () => {
{modelData.source && <Text variant="subtext">Source: {modelData.source}</Text>}
</Flex>
<Button size="sm" leftIcon={<IoPencil />} colorScheme="invokeYellow" onClick={handleEditModel}>
Edit
</Button>
<Flex gap={2}>
<Button size="sm" leftIcon={<IoPencil />} colorScheme="invokeYellow" onClick={handleEditModel}>
Edit
</Button>
{modelData.type === 'main' && modelData.format === 'checkpoint' && <ModelConvert model={modelData} />}
</Flex>
</Flex>
<Flex flexDir="column" p={2} gap={3}>