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
c3f4e87a6e
commit
9b1f63379a
@ -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;
|
||||
};
|
||||
|
||||
export const modelManagerPersistConfig: PersistConfig<ModelManagerState> = {
|
||||
export const modelManagerV2PersistConfig: PersistConfig<ModelManagerState> = {
|
||||
name: modelManagerV2Slice.name,
|
||||
initialState: initialModelManagerState,
|
||||
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 { 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 />
|
||||
|
@ -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"
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={Boolean(errors)}
|
||||
isDisabled={Boolean(Object.keys(errors).length)}
|
||||
>
|
||||
Save
|
||||
</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 { 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}>
|
||||
|
Loading…
Reference in New Issue
Block a user