mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
add model convert to checkpoint main models
This commit is contained in:
parent
dd9b139e38
commit
af9a62d224
@ -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';
|
@ -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';
|
@ -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 };
|
||||||
|
};
|
@ -52,7 +52,7 @@ export const migrateModelManagerState = (state: any): any => {
|
|||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const modelManagerPersistConfig: PersistConfig<ModelManagerState> = {
|
export const modelManagerV2PersistConfig: PersistConfig<ModelManagerState> = {
|
||||||
name: modelManagerV2Slice.name,
|
name: modelManagerV2Slice.name,
|
||||||
initialState: initialModelManagerState,
|
initialState: initialModelManagerState,
|
||||||
migrate: migrateModelManagerState,
|
migrate: migrateModelManagerState,
|
||||||
|
@ -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);
|
|
@ -1,6 +1,6 @@
|
|||||||
import { Box, Button, Flex, Heading } from '@invoke-ai/ui-library';
|
import { Box, Button, Flex, Heading } from '@invoke-ai/ui-library';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
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 { setSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
@ -20,12 +20,9 @@ export const ModelManager = () => {
|
|||||||
<Heading fontSize="xl">Model Manager</Heading>
|
<Heading fontSize="xl">Model Manager</Heading>
|
||||||
<SyncModelsIconButton />
|
<SyncModelsIconButton />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex gap={2}>
|
<Button colorScheme="invokeYellow" onClick={handleClickAddModel}>
|
||||||
<Button colorScheme="invokeYellow" onClick={handleClickAddModel}>
|
Add Models
|
||||||
Add Model
|
</Button>
|
||||||
</Button>
|
|
||||||
<Button>Scan for Models</Button>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
<Box layerStyle="second" p={3} borderRadius="base" w="full" h="full">
|
<Box layerStyle="second" p={3} borderRadius="base" w="full" h="full">
|
||||||
<ModelListNavigation />
|
<ModelListNavigation />
|
||||||
|
@ -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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -171,7 +171,7 @@ export const ModelEdit = () => {
|
|||||||
colorScheme="invokeYellow"
|
colorScheme="invokeYellow"
|
||||||
onClick={handleSubmit(onSubmit)}
|
onClick={handleSubmit(onSubmit)}
|
||||||
isLoading={isSubmitting}
|
isLoading={isSubmitting}
|
||||||
isDisabled={Boolean(errors)}
|
isDisabled={Boolean(Object.keys(errors).length)}
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -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 { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
|
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
|
||||||
import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
import { setSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { IoPencil } from 'react-icons/io5';
|
import { IoPencil } from 'react-icons/io5';
|
||||||
import { useGetModelConfigQuery,useGetModelMetadataQuery } from 'services/api/endpoints/models';
|
import { useGetModelConfigQuery, useGetModelMetadataQuery } from 'services/api/endpoints/models';
|
||||||
import type {
|
import type {
|
||||||
CheckpointModelConfig,
|
CheckpointModelConfig,
|
||||||
ControlNetModelConfig,
|
ControlNetModelConfig,
|
||||||
@ -18,6 +18,7 @@ import type {
|
|||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
|
|
||||||
import { ModelAttrView } from './ModelAttrView';
|
import { ModelAttrView } from './ModelAttrView';
|
||||||
|
import { ModelConvert } from './ModelConvert';
|
||||||
|
|
||||||
export const ModelView = () => {
|
export const ModelView = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
@ -79,9 +80,12 @@ export const ModelView = () => {
|
|||||||
|
|
||||||
{modelData.source && <Text variant="subtext">Source: {modelData.source}</Text>}
|
{modelData.source && <Text variant="subtext">Source: {modelData.source}</Text>}
|
||||||
</Flex>
|
</Flex>
|
||||||
<Button size="sm" leftIcon={<IoPencil />} colorScheme="invokeYellow" onClick={handleEditModel}>
|
<Flex gap={2}>
|
||||||
Edit
|
<Button size="sm" leftIcon={<IoPencil />} colorScheme="invokeYellow" onClick={handleEditModel}>
|
||||||
</Button>
|
Edit
|
||||||
|
</Button>
|
||||||
|
{modelData.type === 'main' && modelData.format === 'checkpoint' && <ModelConvert model={modelData} />}
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex flexDir="column" p={2} gap={3}>
|
<Flex flexDir="column" p={2} gap={3}>
|
||||||
|
Loading…
Reference in New Issue
Block a user