mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'mm-ui' of github.com:blessedcoolant/InvokeAI into mm-ui
This commit is contained in:
commit
84a13ff8e1
@ -16,6 +16,7 @@ from .base import (
|
|||||||
calc_model_size_by_data,
|
calc_model_size_by_data,
|
||||||
classproperty,
|
classproperty,
|
||||||
InvalidModelException,
|
InvalidModelException,
|
||||||
|
ModelNotFoundException,
|
||||||
)
|
)
|
||||||
from invokeai.app.services.config import InvokeAIAppConfig
|
from invokeai.app.services.config import InvokeAIAppConfig
|
||||||
from diffusers.utils import is_safetensors_available
|
from diffusers.utils import is_safetensors_available
|
||||||
|
@ -399,6 +399,8 @@
|
|||||||
"deleteModel": "Delete Model",
|
"deleteModel": "Delete Model",
|
||||||
"deleteConfig": "Delete Config",
|
"deleteConfig": "Delete Config",
|
||||||
"deleteMsg1": "Are you sure you want to delete this model from InvokeAI?",
|
"deleteMsg1": "Are you sure you want to delete this model from InvokeAI?",
|
||||||
|
"modelDeleted": "Model Deleted",
|
||||||
|
"modelDeleteFailed": "Failed to delete model",
|
||||||
"deleteMsg2": "This WILL delete the model from disk if it is in the InvokeAI root folder. If you are using a custom location, then the model WILL NOT be deleted from disk.",
|
"deleteMsg2": "This WILL delete the model from disk if it is in the InvokeAI root folder. If you are using a custom location, then the model WILL NOT be deleted from disk.",
|
||||||
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
"formMessageDiffusersModelLocation": "Diffusers Model Location",
|
||||||
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
|
||||||
@ -408,11 +410,13 @@
|
|||||||
"convertToDiffusers": "Convert To Diffusers",
|
"convertToDiffusers": "Convert To Diffusers",
|
||||||
"convertToDiffusersHelpText1": "This model will be converted to the 🧨 Diffusers format.",
|
"convertToDiffusersHelpText1": "This model will be converted to the 🧨 Diffusers format.",
|
||||||
"convertToDiffusersHelpText2": "This process will replace your Model Manager entry with the Diffusers version of the same model.",
|
"convertToDiffusersHelpText2": "This process will replace your Model Manager entry with the Diffusers version of the same model.",
|
||||||
"convertToDiffusersHelpText3": "Your checkpoint file on the disk will NOT be deleted or modified in anyway. You can add your checkpoint to the Model Manager again if you want to.",
|
"convertToDiffusersHelpText3": "Your checkpoint file on disk WILL be deleted if it is in InvokeAI root folder. If it is in a custom location, then it WILL NOT be deleted.",
|
||||||
"convertToDiffusersHelpText4": "This is a one time process only. It might take around 30s-60s depending on the specifications of your computer.",
|
"convertToDiffusersHelpText4": "This is a one time process only. It might take around 30s-60s depending on the specifications of your computer.",
|
||||||
"convertToDiffusersHelpText5": "Please make sure you have enough disk space. Models generally vary between 2GB-7GB in size.",
|
"convertToDiffusersHelpText5": "Please make sure you have enough disk space. Models generally vary between 2GB-7GB in size.",
|
||||||
"convertToDiffusersHelpText6": "Do you wish to convert this model?",
|
"convertToDiffusersHelpText6": "Do you wish to convert this model?",
|
||||||
"convertToDiffusersSaveLocation": "Save Location",
|
"convertToDiffusersSaveLocation": "Save Location",
|
||||||
|
"noCustomLocationProvided": "No Custom Location Provided",
|
||||||
|
"convertingModelBegin": "Converting Model. Please wait.",
|
||||||
"v1": "v1",
|
"v1": "v1",
|
||||||
"v2_base": "v2 (512px)",
|
"v2_base": "v2 (512px)",
|
||||||
"v2_768": "v2 (768px)",
|
"v2_768": "v2 (768px)",
|
||||||
@ -450,7 +454,8 @@
|
|||||||
"none": "none",
|
"none": "none",
|
||||||
"addDifference": "Add Difference",
|
"addDifference": "Add Difference",
|
||||||
"pickModelType": "Pick Model Type",
|
"pickModelType": "Pick Model Type",
|
||||||
"selectModel": "Select Model"
|
"selectModel": "Select Model",
|
||||||
|
"importModels": "Import Models"
|
||||||
},
|
},
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"general": "General",
|
"general": "General",
|
||||||
|
@ -21,6 +21,7 @@ import generationReducer from 'features/parameters/store/generationSlice';
|
|||||||
import postprocessingReducer from 'features/parameters/store/postprocessingSlice';
|
import postprocessingReducer from 'features/parameters/store/postprocessingSlice';
|
||||||
import configReducer from 'features/system/store/configSlice';
|
import configReducer from 'features/system/store/configSlice';
|
||||||
import systemReducer from 'features/system/store/systemSlice';
|
import systemReducer from 'features/system/store/systemSlice';
|
||||||
|
import modelmanagerReducer from 'features/ui/components/tabs/ModelManager/store/modelManagerSlice';
|
||||||
import hotkeysReducer from 'features/ui/store/hotkeysSlice';
|
import hotkeysReducer from 'features/ui/store/hotkeysSlice';
|
||||||
import uiReducer from 'features/ui/store/uiSlice';
|
import uiReducer from 'features/ui/store/uiSlice';
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ const allReducers = {
|
|||||||
dynamicPrompts: dynamicPromptsReducer,
|
dynamicPrompts: dynamicPromptsReducer,
|
||||||
imageDeletion: imageDeletionReducer,
|
imageDeletion: imageDeletionReducer,
|
||||||
lora: loraReducer,
|
lora: loraReducer,
|
||||||
|
modelmanager: modelmanagerReducer,
|
||||||
[api.reducerPath]: api.reducer,
|
[api.reducerPath]: api.reducer,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,6 +69,7 @@ const rememberedKeys: (keyof typeof allReducers)[] = [
|
|||||||
'controlNet',
|
'controlNet',
|
||||||
'dynamicPrompts',
|
'dynamicPrompts',
|
||||||
'lora',
|
'lora',
|
||||||
|
'modelmanager',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
|
@ -36,6 +36,7 @@ export default function IAIMantineTextInput(props: IAIMantineTextInputProps) {
|
|||||||
label: {
|
label: {
|
||||||
color: mode(base700, base300)(colorMode),
|
color: mode(base700, base300)(colorMode),
|
||||||
fontWeight: 'normal',
|
fontWeight: 'normal',
|
||||||
|
marginBottom: 4,
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
{...rest}
|
{...rest}
|
||||||
|
@ -9,14 +9,14 @@ export type IAISelectDataType = {
|
|||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IAISelectProps = Omit<SelectProps, 'label'> & {
|
export type IAISelectProps = Omit<SelectProps, 'label'> & {
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
inputRef?: RefObject<HTMLInputElement>;
|
inputRef?: RefObject<HTMLInputElement>;
|
||||||
label?: string;
|
label?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const IAIMantineSelect = (props: IAISelectProps) => {
|
const IAIMantineSelect = (props: IAISelectProps) => {
|
||||||
const { tooltip, inputRef, label, disabled, ...rest } = props;
|
const { tooltip, inputRef, label, disabled, required, ...rest } = props;
|
||||||
|
|
||||||
const styles = useMantineSelectStyles();
|
const styles = useMantineSelectStyles();
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ const IAIMantineSelect = (props: IAISelectProps) => {
|
|||||||
<Select
|
<Select
|
||||||
label={
|
label={
|
||||||
label ? (
|
label ? (
|
||||||
<FormControl isDisabled={disabled}>
|
<FormControl isRequired={required} isDisabled={disabled}>
|
||||||
<FormLabel>{label}</FormLabel>
|
<FormLabel>{label}</FormLabel>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
) : undefined
|
) : undefined
|
||||||
|
@ -16,14 +16,13 @@ import {
|
|||||||
ASSETS_CATEGORIES,
|
ASSETS_CATEGORIES,
|
||||||
IMAGE_CATEGORIES,
|
IMAGE_CATEGORIES,
|
||||||
IMAGE_LIMIT,
|
IMAGE_LIMIT,
|
||||||
selectImagesAll,
|
|
||||||
} from 'features/gallery//store/gallerySlice';
|
} from 'features/gallery//store/gallerySlice';
|
||||||
import { selectFilteredImages } from 'features/gallery/store/gallerySelectors';
|
import { selectFilteredImages } from 'features/gallery/store/gallerySelectors';
|
||||||
import { VirtuosoGrid } from 'react-virtuoso';
|
import { VirtuosoGrid } from 'react-virtuoso';
|
||||||
import { receivedPageOfImages } from 'services/api/thunks/image';
|
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||||
|
import { useListBoardImagesQuery } from '../../../../services/api/endpoints/boardImages';
|
||||||
import ImageGridItemContainer from './ImageGridItemContainer';
|
import ImageGridItemContainer from './ImageGridItemContainer';
|
||||||
import ImageGridListContainer from './ImageGridListContainer';
|
import ImageGridListContainer from './ImageGridListContainer';
|
||||||
import { useListBoardImagesQuery } from '../../../../services/api/endpoints/boardImages';
|
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[stateSelector, selectFilteredImages],
|
[stateSelector, selectFilteredImages],
|
||||||
@ -180,7 +179,6 @@ const GalleryImageGrid = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log({ selectedBoardId });
|
|
||||||
|
|
||||||
if (status !== 'rejected') {
|
if (status !== 'rejected') {
|
||||||
return (
|
return (
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { UseToastOptions } from '@chakra-ui/react';
|
import { UseToastOptions } from '@chakra-ui/react';
|
||||||
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||||
import * as InvokeAI from 'app/types/invokeai';
|
|
||||||
|
|
||||||
import { InvokeLogLevel } from 'app/logging/useLogger';
|
import { InvokeLogLevel } from 'app/logging/useLogger';
|
||||||
import { userInvoked } from 'app/store/actions';
|
import { userInvoked } from 'app/store/actions';
|
||||||
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
|
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
|
||||||
import { TFuncKey, t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { LogLevelName } from 'roarr';
|
import { LogLevelName } from 'roarr';
|
||||||
import { imageUploaded } from 'services/api/thunks/image';
|
import { imageUploaded } from 'services/api/thunks/image';
|
||||||
import {
|
import {
|
||||||
@ -44,8 +43,6 @@ export interface SystemState {
|
|||||||
isCancelable: boolean;
|
isCancelable: boolean;
|
||||||
enableImageDebugging: boolean;
|
enableImageDebugging: boolean;
|
||||||
toastQueue: UseToastOptions[];
|
toastQueue: UseToastOptions[];
|
||||||
searchFolder: string | null;
|
|
||||||
foundModels: InvokeAI.FoundModel[] | null;
|
|
||||||
/**
|
/**
|
||||||
* The current progress image
|
* The current progress image
|
||||||
*/
|
*/
|
||||||
@ -79,7 +76,7 @@ export interface SystemState {
|
|||||||
*/
|
*/
|
||||||
consoleLogLevel: InvokeLogLevel;
|
consoleLogLevel: InvokeLogLevel;
|
||||||
shouldLogToConsole: boolean;
|
shouldLogToConsole: boolean;
|
||||||
statusTranslationKey: TFuncKey;
|
statusTranslationKey: any;
|
||||||
/**
|
/**
|
||||||
* When a session is canceled, its ID is stored here until a new session is created.
|
* When a session is canceled, its ID is stored here until a new session is created.
|
||||||
*/
|
*/
|
||||||
@ -106,8 +103,6 @@ export const initialSystemState: SystemState = {
|
|||||||
isCancelable: true,
|
isCancelable: true,
|
||||||
enableImageDebugging: false,
|
enableImageDebugging: false,
|
||||||
toastQueue: [],
|
toastQueue: [],
|
||||||
searchFolder: null,
|
|
||||||
foundModels: null,
|
|
||||||
progressImage: null,
|
progressImage: null,
|
||||||
shouldAntialiasProgressImage: false,
|
shouldAntialiasProgressImage: false,
|
||||||
sessionId: null,
|
sessionId: null,
|
||||||
@ -132,7 +127,7 @@ export const systemSlice = createSlice({
|
|||||||
setIsProcessing: (state, action: PayloadAction<boolean>) => {
|
setIsProcessing: (state, action: PayloadAction<boolean>) => {
|
||||||
state.isProcessing = action.payload;
|
state.isProcessing = action.payload;
|
||||||
},
|
},
|
||||||
setCurrentStatus: (state, action: PayloadAction<TFuncKey>) => {
|
setCurrentStatus: (state, action: any) => {
|
||||||
state.statusTranslationKey = action.payload;
|
state.statusTranslationKey = action.payload;
|
||||||
},
|
},
|
||||||
setShouldConfirmOnDelete: (state, action: PayloadAction<boolean>) => {
|
setShouldConfirmOnDelete: (state, action: PayloadAction<boolean>) => {
|
||||||
@ -153,15 +148,6 @@ export const systemSlice = createSlice({
|
|||||||
clearToastQueue: (state) => {
|
clearToastQueue: (state) => {
|
||||||
state.toastQueue = [];
|
state.toastQueue = [];
|
||||||
},
|
},
|
||||||
setSearchFolder: (state, action: PayloadAction<string | null>) => {
|
|
||||||
state.searchFolder = action.payload;
|
|
||||||
},
|
|
||||||
setFoundModels: (
|
|
||||||
state,
|
|
||||||
action: PayloadAction<InvokeAI.FoundModel[] | null>
|
|
||||||
) => {
|
|
||||||
state.foundModels = action.payload;
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* A cancel was scheduled
|
* A cancel was scheduled
|
||||||
*/
|
*/
|
||||||
@ -426,8 +412,6 @@ export const {
|
|||||||
setEnableImageDebugging,
|
setEnableImageDebugging,
|
||||||
addToast,
|
addToast,
|
||||||
clearToastQueue,
|
clearToastQueue,
|
||||||
setSearchFolder,
|
|
||||||
setFoundModels,
|
|
||||||
cancelScheduled,
|
cancelScheduled,
|
||||||
scheduledCancelAborted,
|
scheduledCancelAborted,
|
||||||
cancelTypeChanged,
|
cancelTypeChanged,
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/react';
|
import { Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/react';
|
||||||
import i18n from 'i18n';
|
import i18n from 'i18n';
|
||||||
import { ReactNode, memo } from 'react';
|
import { ReactNode, memo } from 'react';
|
||||||
import AddModelsPanel from './subpanels/AddModelsPanel';
|
import ImportModelsPanel from './subpanels/ImportModelsPanel';
|
||||||
import MergeModelsPanel from './subpanels/MergeModelsPanel';
|
import MergeModelsPanel from './subpanels/MergeModelsPanel';
|
||||||
import ModelManagerPanel from './subpanels/ModelManagerPanel';
|
import ModelManagerPanel from './subpanels/ModelManagerPanel';
|
||||||
|
|
||||||
type ModelManagerTabName = 'modelManager' | 'addModels' | 'mergeModels';
|
type ModelManagerTabName = 'modelManager' | 'importModels' | 'mergeModels';
|
||||||
|
|
||||||
type ModelManagerTabInfo = {
|
type ModelManagerTabInfo = {
|
||||||
id: ModelManagerTabName;
|
id: ModelManagerTabName;
|
||||||
@ -20,9 +20,9 @@ const tabs: ModelManagerTabInfo[] = [
|
|||||||
content: <ModelManagerPanel />,
|
content: <ModelManagerPanel />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'addModels',
|
id: 'importModels',
|
||||||
label: i18n.t('modelManager.addModel'),
|
label: i18n.t('modelManager.importModels'),
|
||||||
content: <AddModelsPanel />,
|
content: <ImportModelsPanel />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'mergeModels',
|
id: 'mergeModels',
|
||||||
@ -46,7 +46,7 @@ const ModelManagerTab = () => {
|
|||||||
</Tab>
|
</Tab>
|
||||||
))}
|
))}
|
||||||
</TabList>
|
</TabList>
|
||||||
<TabPanels sx={{ w: 'full', h: 'full', p: 4 }}>
|
<TabPanels sx={{ w: 'full', h: 'full' }}>
|
||||||
{tabs.map((tab) => (
|
{tabs.map((tab) => (
|
||||||
<TabPanel sx={{ w: 'full', h: 'full' }} key={tab.id}>
|
<TabPanel sx={{ w: 'full', h: 'full' }} key={tab.id}>
|
||||||
{tab.content}
|
{tab.content}
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
type ModelManagerState = {
|
||||||
|
searchFolder: string | null;
|
||||||
|
advancedAddScanModel: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialModelManagerState: ModelManagerState = {
|
||||||
|
searchFolder: null,
|
||||||
|
advancedAddScanModel: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const modelManagerSlice = createSlice({
|
||||||
|
name: 'modelmanager',
|
||||||
|
initialState: initialModelManagerState,
|
||||||
|
reducers: {
|
||||||
|
setSearchFolder: (state, action: PayloadAction<string | null>) => {
|
||||||
|
state.searchFolder = action.payload;
|
||||||
|
},
|
||||||
|
setAdvancedAddScanModel: (state, action: PayloadAction<string | null>) => {
|
||||||
|
state.advancedAddScanModel = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { setSearchFolder, setAdvancedAddScanModel } =
|
||||||
|
modelManagerSlice.actions;
|
||||||
|
|
||||||
|
export default modelManagerSlice.reducer;
|
@ -0,0 +1,3 @@
|
|||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
|
||||||
|
export const modelmanagerSelector = (state: RootState) => state.modelmanager;
|
@ -1,43 +0,0 @@
|
|||||||
import { Divider, Flex, useColorMode } from '@chakra-ui/react';
|
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
|
||||||
import { setAddNewModelUIOption } from 'features/ui/store/uiSlice';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import AddCheckpointModel from './AddModelsPanel/AddCheckpointModel';
|
|
||||||
import AddDiffusersModel from './AddModelsPanel/AddDiffusersModel';
|
|
||||||
|
|
||||||
export default function AddModelsPanel() {
|
|
||||||
const addNewModelUIOption = useAppSelector(
|
|
||||||
(state: RootState) => state.ui.addNewModelUIOption
|
|
||||||
);
|
|
||||||
|
|
||||||
const { colorMode } = useColorMode();
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex flexDirection="column" gap={4}>
|
|
||||||
<Flex columnGap={4}>
|
|
||||||
<IAIButton
|
|
||||||
onClick={() => dispatch(setAddNewModelUIOption('ckpt'))}
|
|
||||||
isChecked={addNewModelUIOption == 'ckpt'}
|
|
||||||
>
|
|
||||||
{t('modelManager.addCheckpointModel')}
|
|
||||||
</IAIButton>
|
|
||||||
<IAIButton
|
|
||||||
onClick={() => dispatch(setAddNewModelUIOption('diffusers'))}
|
|
||||||
isChecked={addNewModelUIOption == 'diffusers'}
|
|
||||||
>
|
|
||||||
{t('modelManager.addDiffuserModel')}
|
|
||||||
</IAIButton>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
{addNewModelUIOption == 'ckpt' && <AddCheckpointModel />}
|
|
||||||
{addNewModelUIOption == 'diffusers' && <AddDiffusersModel />}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,337 +0,0 @@
|
|||||||
import {
|
|
||||||
Flex,
|
|
||||||
FormControl,
|
|
||||||
FormErrorMessage,
|
|
||||||
FormHelperText,
|
|
||||||
FormLabel,
|
|
||||||
HStack,
|
|
||||||
Text,
|
|
||||||
VStack,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
|
||||||
import IAIInput from 'common/components/IAIInput';
|
|
||||||
import IAINumberInput from 'common/components/IAINumberInput';
|
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
// import { addNewModel } from 'app/socketio/actions';
|
|
||||||
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
|
|
||||||
import { Field, Formik } from 'formik';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
import type { RootState } from 'app/store/store';
|
|
||||||
import type { InvokeModelConfigProps } from 'app/types/invokeai';
|
|
||||||
import IAIForm from 'common/components/IAIForm';
|
|
||||||
import { IAIFormItemWrapper } from 'common/components/IAIForms/IAIFormItemWrapper';
|
|
||||||
import { setAddNewModelUIOption } from 'features/ui/store/uiSlice';
|
|
||||||
import type { FieldInputProps, FormikProps } from 'formik';
|
|
||||||
import SearchModels from './SearchModels';
|
|
||||||
|
|
||||||
const MIN_MODEL_SIZE = 64;
|
|
||||||
const MAX_MODEL_SIZE = 2048;
|
|
||||||
|
|
||||||
export default function AddCheckpointModel() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const isProcessing = useAppSelector(
|
|
||||||
(state: RootState) => state.system.isProcessing
|
|
||||||
);
|
|
||||||
|
|
||||||
function hasWhiteSpace(s: string) {
|
|
||||||
return /\s/.test(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
function baseValidation(value: string) {
|
|
||||||
let error;
|
|
||||||
if (hasWhiteSpace(value)) error = t('modelManager.cannotUseSpaces');
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const addModelFormValues: InvokeModelConfigProps = {
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
config: 'configs/stable-diffusion/v1-inference.yaml',
|
|
||||||
weights: '',
|
|
||||||
vae: '',
|
|
||||||
width: 512,
|
|
||||||
height: 512,
|
|
||||||
format: 'ckpt',
|
|
||||||
default: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const addModelFormSubmitHandler = (values: InvokeModelConfigProps) => {
|
|
||||||
dispatch(addNewModel(values));
|
|
||||||
dispatch(setAddNewModelUIOption(null));
|
|
||||||
};
|
|
||||||
|
|
||||||
const [addManually, setAddmanually] = React.useState<boolean>(false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<VStack gap={2} alignItems="flex-start">
|
|
||||||
<Flex columnGap={4}>
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
isChecked={!addManually}
|
|
||||||
label={t('modelManager.scanForModels')}
|
|
||||||
onChange={() => setAddmanually(!addManually)}
|
|
||||||
/>
|
|
||||||
<IAISimpleCheckbox
|
|
||||||
label={t('modelManager.addManually')}
|
|
||||||
isChecked={addManually}
|
|
||||||
onChange={() => setAddmanually(!addManually)}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
{addManually ? (
|
|
||||||
<Formik
|
|
||||||
initialValues={addModelFormValues}
|
|
||||||
onSubmit={addModelFormSubmitHandler}
|
|
||||||
>
|
|
||||||
{({ handleSubmit, errors, touched }) => (
|
|
||||||
<IAIForm onSubmit={handleSubmit} sx={{ w: 'full' }}>
|
|
||||||
<VStack rowGap={2}>
|
|
||||||
<Text fontSize={20} fontWeight="bold" alignSelf="start">
|
|
||||||
{t('modelManager.manual')}
|
|
||||||
</Text>
|
|
||||||
{/* Name */}
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
<FormControl
|
|
||||||
isInvalid={!!errors.name && touched.name}
|
|
||||||
isRequired
|
|
||||||
>
|
|
||||||
<FormLabel htmlFor="name" fontSize="sm">
|
|
||||||
{t('modelManager.name')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
type="text"
|
|
||||||
validate={baseValidation}
|
|
||||||
width="full"
|
|
||||||
/>
|
|
||||||
{!!errors.name && touched.name ? (
|
|
||||||
<FormErrorMessage>{errors.name}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.nameValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
{/* Description */}
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
<FormControl
|
|
||||||
isInvalid={!!errors.description && touched.description}
|
|
||||||
isRequired
|
|
||||||
>
|
|
||||||
<FormLabel htmlFor="description" fontSize="sm">
|
|
||||||
{t('modelManager.description')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="description"
|
|
||||||
name="description"
|
|
||||||
type="text"
|
|
||||||
width="full"
|
|
||||||
/>
|
|
||||||
{!!errors.description && touched.description ? (
|
|
||||||
<FormErrorMessage>
|
|
||||||
{errors.description}
|
|
||||||
</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.descriptionValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
{/* Config */}
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
<FormControl
|
|
||||||
isInvalid={!!errors.config && touched.config}
|
|
||||||
isRequired
|
|
||||||
>
|
|
||||||
<FormLabel htmlFor="config" fontSize="sm">
|
|
||||||
{t('modelManager.config')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="config"
|
|
||||||
name="config"
|
|
||||||
type="text"
|
|
||||||
width="full"
|
|
||||||
/>
|
|
||||||
{!!errors.config && touched.config ? (
|
|
||||||
<FormErrorMessage>{errors.config}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.configValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
{/* Weights */}
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
<FormControl
|
|
||||||
isInvalid={!!errors.weights && touched.weights}
|
|
||||||
isRequired
|
|
||||||
>
|
|
||||||
<FormLabel htmlFor="config" fontSize="sm">
|
|
||||||
{t('modelManager.modelLocation')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="weights"
|
|
||||||
name="weights"
|
|
||||||
type="text"
|
|
||||||
width="full"
|
|
||||||
/>
|
|
||||||
{!!errors.weights && touched.weights ? (
|
|
||||||
<FormErrorMessage>{errors.weights}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.modelLocationValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
{/* VAE */}
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
<FormControl isInvalid={!!errors.vae && touched.vae}>
|
|
||||||
<FormLabel htmlFor="vae" fontSize="sm">
|
|
||||||
{t('modelManager.vaeLocation')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="vae"
|
|
||||||
name="vae"
|
|
||||||
type="text"
|
|
||||||
width="full"
|
|
||||||
/>
|
|
||||||
{!!errors.vae && touched.vae ? (
|
|
||||||
<FormErrorMessage>{errors.vae}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.vaeLocationValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
<HStack width="100%">
|
|
||||||
{/* Width */}
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
<FormControl isInvalid={!!errors.width && touched.width}>
|
|
||||||
<FormLabel htmlFor="width" fontSize="sm">
|
|
||||||
{t('modelManager.width')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field id="width" name="width">
|
|
||||||
{({
|
|
||||||
field,
|
|
||||||
form,
|
|
||||||
}: {
|
|
||||||
field: FieldInputProps<number>;
|
|
||||||
form: FormikProps<InvokeModelConfigProps>;
|
|
||||||
}) => (
|
|
||||||
<IAINumberInput
|
|
||||||
id="width"
|
|
||||||
name="width"
|
|
||||||
min={MIN_MODEL_SIZE}
|
|
||||||
max={MAX_MODEL_SIZE}
|
|
||||||
step={64}
|
|
||||||
value={form.values.width}
|
|
||||||
onChange={(value) =>
|
|
||||||
form.setFieldValue(field.name, Number(value))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
{!!errors.width && touched.width ? (
|
|
||||||
<FormErrorMessage>{errors.width}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.widthValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
{/* Height */}
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
<FormControl isInvalid={!!errors.height && touched.height}>
|
|
||||||
<FormLabel htmlFor="height" fontSize="sm">
|
|
||||||
{t('modelManager.height')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field id="height" name="height">
|
|
||||||
{({
|
|
||||||
field,
|
|
||||||
form,
|
|
||||||
}: {
|
|
||||||
field: FieldInputProps<number>;
|
|
||||||
form: FormikProps<InvokeModelConfigProps>;
|
|
||||||
}) => (
|
|
||||||
<IAINumberInput
|
|
||||||
id="height"
|
|
||||||
name="height"
|
|
||||||
min={MIN_MODEL_SIZE}
|
|
||||||
max={MAX_MODEL_SIZE}
|
|
||||||
step={64}
|
|
||||||
value={form.values.height}
|
|
||||||
onChange={(value) =>
|
|
||||||
form.setFieldValue(field.name, Number(value))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
{!!errors.height && touched.height ? (
|
|
||||||
<FormErrorMessage>{errors.height}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.heightValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
</HStack>
|
|
||||||
|
|
||||||
<IAIButton
|
|
||||||
type="submit"
|
|
||||||
className="modal-close-btn"
|
|
||||||
isLoading={isProcessing}
|
|
||||||
>
|
|
||||||
{t('modelManager.addModel')}
|
|
||||||
</IAIButton>
|
|
||||||
</VStack>
|
|
||||||
</IAIForm>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
) : (
|
|
||||||
<SearchModels />
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,259 +0,0 @@
|
|||||||
import {
|
|
||||||
Flex,
|
|
||||||
FormControl,
|
|
||||||
FormErrorMessage,
|
|
||||||
FormHelperText,
|
|
||||||
FormLabel,
|
|
||||||
Text,
|
|
||||||
VStack,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { InvokeDiffusersModelConfigProps } from 'app/types/invokeai';
|
|
||||||
// import { addNewModel } from 'app/socketio/actions';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
|
||||||
import IAIInput from 'common/components/IAIInput';
|
|
||||||
import { setAddNewModelUIOption } from 'features/ui/store/uiSlice';
|
|
||||||
import { Field, Formik } from 'formik';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
import type { RootState } from 'app/store/store';
|
|
||||||
import IAIForm from 'common/components/IAIForm';
|
|
||||||
import { IAIFormItemWrapper } from 'common/components/IAIForms/IAIFormItemWrapper';
|
|
||||||
|
|
||||||
export default function AddDiffusersModel() {
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const isProcessing = useAppSelector(
|
|
||||||
(state: RootState) => state.system.isProcessing
|
|
||||||
);
|
|
||||||
|
|
||||||
function hasWhiteSpace(s: string) {
|
|
||||||
return /\s/.test(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
function baseValidation(value: string) {
|
|
||||||
let error;
|
|
||||||
if (hasWhiteSpace(value)) error = t('modelManager.cannotUseSpaces');
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const addModelFormValues: InvokeDiffusersModelConfigProps = {
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
repo_id: '',
|
|
||||||
path: '',
|
|
||||||
format: 'diffusers',
|
|
||||||
default: false,
|
|
||||||
vae: {
|
|
||||||
repo_id: '',
|
|
||||||
path: '',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const addModelFormSubmitHandler = (
|
|
||||||
values: InvokeDiffusersModelConfigProps
|
|
||||||
) => {
|
|
||||||
const diffusersModelToAdd = values;
|
|
||||||
|
|
||||||
if (values.path === '') delete diffusersModelToAdd.path;
|
|
||||||
if (values.repo_id === '') delete diffusersModelToAdd.repo_id;
|
|
||||||
if (values.vae.path === '') delete diffusersModelToAdd.vae.path;
|
|
||||||
if (values.vae.repo_id === '') delete diffusersModelToAdd.vae.repo_id;
|
|
||||||
|
|
||||||
dispatch(addNewModel(diffusersModelToAdd));
|
|
||||||
dispatch(setAddNewModelUIOption(null));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex overflow="scroll" maxHeight={window.innerHeight - 270} width="100%">
|
|
||||||
<Formik
|
|
||||||
initialValues={addModelFormValues}
|
|
||||||
onSubmit={addModelFormSubmitHandler}
|
|
||||||
>
|
|
||||||
{({ handleSubmit, errors, touched }) => (
|
|
||||||
<IAIForm onSubmit={handleSubmit} w="full">
|
|
||||||
<VStack rowGap={2}>
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
{/* Name */}
|
|
||||||
<FormControl
|
|
||||||
isInvalid={!!errors.name && touched.name}
|
|
||||||
isRequired
|
|
||||||
>
|
|
||||||
<FormLabel htmlFor="name" fontSize="sm">
|
|
||||||
{t('modelManager.name')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
type="text"
|
|
||||||
validate={baseValidation}
|
|
||||||
isRequired
|
|
||||||
/>
|
|
||||||
{!!errors.name && touched.name ? (
|
|
||||||
<FormErrorMessage>{errors.name}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.nameValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
{/* Description */}
|
|
||||||
<FormControl
|
|
||||||
isInvalid={!!errors.description && touched.description}
|
|
||||||
isRequired
|
|
||||||
>
|
|
||||||
<FormLabel htmlFor="description" fontSize="sm">
|
|
||||||
{t('modelManager.description')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="description"
|
|
||||||
name="description"
|
|
||||||
type="text"
|
|
||||||
isRequired
|
|
||||||
/>
|
|
||||||
{!!errors.description && touched.description ? (
|
|
||||||
<FormErrorMessage>{errors.description}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.descriptionValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
<Text fontWeight="bold" fontSize="sm">
|
|
||||||
{t('modelManager.formMessageDiffusersModelLocation')}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
sx={{
|
|
||||||
fontSize: 'sm',
|
|
||||||
fontStyle: 'italic',
|
|
||||||
}}
|
|
||||||
variant="subtext"
|
|
||||||
>
|
|
||||||
{t('modelManager.formMessageDiffusersModelLocationDesc')}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
{/* Path */}
|
|
||||||
<FormControl isInvalid={!!errors.path && touched.path}>
|
|
||||||
<FormLabel htmlFor="path" fontSize="sm">
|
|
||||||
{t('modelManager.modelLocation')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field as={IAIInput} id="path" name="path" type="text" />
|
|
||||||
{!!errors.path && touched.path ? (
|
|
||||||
<FormErrorMessage>{errors.path}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.modelLocationValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
{/* Repo ID */}
|
|
||||||
<FormControl isInvalid={!!errors.repo_id && touched.repo_id}>
|
|
||||||
<FormLabel htmlFor="repo_id" fontSize="sm">
|
|
||||||
{t('modelManager.repo_id')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="repo_id"
|
|
||||||
name="repo_id"
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
{!!errors.repo_id && touched.repo_id ? (
|
|
||||||
<FormErrorMessage>{errors.repo_id}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.repoIDValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
<IAIFormItemWrapper>
|
|
||||||
{/* VAE Path */}
|
|
||||||
<Text fontWeight="bold">
|
|
||||||
{t('modelManager.formMessageDiffusersVAELocation')}
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
sx={{
|
|
||||||
fontSize: 'sm',
|
|
||||||
fontStyle: 'italic',
|
|
||||||
}}
|
|
||||||
variant="subtext"
|
|
||||||
>
|
|
||||||
{t('modelManager.formMessageDiffusersVAELocationDesc')}
|
|
||||||
</Text>
|
|
||||||
<FormControl
|
|
||||||
isInvalid={!!errors.vae?.path && touched.vae?.path}
|
|
||||||
>
|
|
||||||
<FormLabel htmlFor="vae.path" fontSize="sm">
|
|
||||||
{t('modelManager.vaeLocation')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="vae.path"
|
|
||||||
name="vae.path"
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
{!!errors.vae?.path && touched.vae?.path ? (
|
|
||||||
<FormErrorMessage>{errors.vae?.path}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.vaeLocationValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
{/* VAE Repo ID */}
|
|
||||||
<FormControl
|
|
||||||
isInvalid={!!errors.vae?.repo_id && touched.vae?.repo_id}
|
|
||||||
>
|
|
||||||
<FormLabel htmlFor="vae.repo_id" fontSize="sm">
|
|
||||||
{t('modelManager.vaeRepoID')}
|
|
||||||
</FormLabel>
|
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="vae.repo_id"
|
|
||||||
name="vae.repo_id"
|
|
||||||
type="text"
|
|
||||||
/>
|
|
||||||
{!!errors.vae?.repo_id && touched.vae?.repo_id ? (
|
|
||||||
<FormErrorMessage>{errors.vae?.repo_id}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.vaeRepoIDValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
</IAIFormItemWrapper>
|
|
||||||
|
|
||||||
<IAIButton type="submit" isLoading={isProcessing}>
|
|
||||||
{t('modelManager.addModel')}
|
|
||||||
</IAIButton>
|
|
||||||
</VStack>
|
|
||||||
</IAIForm>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
@ -0,0 +1,48 @@
|
|||||||
|
import { ButtonGroup, Flex } from '@chakra-ui/react';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import AdvancedAddModels from './AdvancedAddModels';
|
||||||
|
import SimpleAddModels from './SimpleAddModels';
|
||||||
|
|
||||||
|
export default function AddModels() {
|
||||||
|
const [addModelMode, setAddModelMode] = useState<'simple' | 'advanced'>(
|
||||||
|
'simple'
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
flexDirection="column"
|
||||||
|
width="100%"
|
||||||
|
overflow="scroll"
|
||||||
|
maxHeight={window.innerHeight - 250}
|
||||||
|
gap={4}
|
||||||
|
>
|
||||||
|
<ButtonGroup isAttached>
|
||||||
|
<IAIButton
|
||||||
|
size="sm"
|
||||||
|
isChecked={addModelMode == 'simple'}
|
||||||
|
onClick={() => setAddModelMode('simple')}
|
||||||
|
>
|
||||||
|
Simple
|
||||||
|
</IAIButton>
|
||||||
|
<IAIButton
|
||||||
|
size="sm"
|
||||||
|
isChecked={addModelMode == 'advanced'}
|
||||||
|
onClick={() => setAddModelMode('advanced')}
|
||||||
|
>
|
||||||
|
Advanced
|
||||||
|
</IAIButton>
|
||||||
|
</ButtonGroup>
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
p: 4,
|
||||||
|
borderRadius: 4,
|
||||||
|
background: 'base.200',
|
||||||
|
_dark: { background: 'base.800' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{addModelMode === 'simple' && <SimpleAddModels />}
|
||||||
|
{addModelMode === 'advanced' && <AdvancedAddModels />}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { useForm } from '@mantine/form';
|
||||||
|
import { makeToast } from 'app/components/Toaster';
|
||||||
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
|
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useAddMainModelsMutation } from 'services/api/endpoints/models';
|
||||||
|
import { CheckpointModelConfig } from 'services/api/types';
|
||||||
|
import { setAdvancedAddScanModel } from '../../store/modelManagerSlice';
|
||||||
|
import BaseModelSelect from '../shared/BaseModelSelect';
|
||||||
|
import CheckpointConfigsSelect from '../shared/CheckpointConfigsSelect';
|
||||||
|
import ModelVariantSelect from '../shared/ModelVariantSelect';
|
||||||
|
|
||||||
|
type AdvancedAddCheckpointProps = {
|
||||||
|
model_path?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AdvancedAddCheckpoint(
|
||||||
|
props: AdvancedAddCheckpointProps
|
||||||
|
) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { model_path } = props;
|
||||||
|
|
||||||
|
const advancedAddCheckpointForm = useForm<CheckpointModelConfig>({
|
||||||
|
initialValues: {
|
||||||
|
model_name: model_path
|
||||||
|
? model_path.split('\\').splice(-1)[0].split('.')[0]
|
||||||
|
: '',
|
||||||
|
base_model: 'sd-1',
|
||||||
|
model_type: 'main',
|
||||||
|
path: model_path ? model_path : '',
|
||||||
|
description: '',
|
||||||
|
model_format: 'checkpoint',
|
||||||
|
error: undefined,
|
||||||
|
vae: '',
|
||||||
|
variant: 'normal',
|
||||||
|
config: 'configs\\stable-diffusion\\v1-inference.yaml',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [addMainModel] = useAddMainModelsMutation();
|
||||||
|
|
||||||
|
const [useCustomConfig, setUseCustomConfig] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const advancedAddCheckpointFormHandler = (values: CheckpointModelConfig) => {
|
||||||
|
addMainModel({
|
||||||
|
body: values,
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.then((_) => {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: `Model Added: ${values.model_name}`,
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
advancedAddCheckpointForm.reset();
|
||||||
|
|
||||||
|
// Close Advanced Panel in Scan Models tab
|
||||||
|
if (model_path) {
|
||||||
|
dispatch(setAdvancedAddScanModel(null));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (error) {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: 'Model Add Failed',
|
||||||
|
status: 'error',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
onSubmit={advancedAddCheckpointForm.onSubmit((v) =>
|
||||||
|
advancedAddCheckpointFormHandler(v)
|
||||||
|
)}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
>
|
||||||
|
<Flex flexDirection="column" gap={2}>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
label="Model Name"
|
||||||
|
required
|
||||||
|
{...advancedAddCheckpointForm.getInputProps('model_name')}
|
||||||
|
/>
|
||||||
|
<BaseModelSelect
|
||||||
|
{...advancedAddCheckpointForm.getInputProps('base_model')}
|
||||||
|
/>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
label="Model Location"
|
||||||
|
required
|
||||||
|
{...advancedAddCheckpointForm.getInputProps('path')}
|
||||||
|
/>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
label="Description"
|
||||||
|
{...advancedAddCheckpointForm.getInputProps('description')}
|
||||||
|
/>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
label="VAE Location"
|
||||||
|
{...advancedAddCheckpointForm.getInputProps('vae')}
|
||||||
|
/>
|
||||||
|
<ModelVariantSelect
|
||||||
|
{...advancedAddCheckpointForm.getInputProps('variant')}
|
||||||
|
/>
|
||||||
|
<Flex flexDirection="column" width="100%" gap={2}>
|
||||||
|
{!useCustomConfig ? (
|
||||||
|
<CheckpointConfigsSelect
|
||||||
|
required
|
||||||
|
width="100%"
|
||||||
|
{...advancedAddCheckpointForm.getInputProps('config')}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<IAIMantineTextInput
|
||||||
|
required
|
||||||
|
label="Custom Config File Location"
|
||||||
|
{...advancedAddCheckpointForm.getInputProps('config')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<IAISimpleCheckbox
|
||||||
|
isChecked={useCustomConfig}
|
||||||
|
onChange={() => setUseCustomConfig(!useCustomConfig)}
|
||||||
|
label="Use Custom Config"
|
||||||
|
/>
|
||||||
|
<IAIButton mt={2} type="submit">
|
||||||
|
{t('modelManager.addModel')}
|
||||||
|
</IAIButton>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { useForm } from '@mantine/form';
|
||||||
|
import { makeToast } from 'app/components/Toaster';
|
||||||
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useAddMainModelsMutation } from 'services/api/endpoints/models';
|
||||||
|
import { DiffusersModelConfig } from 'services/api/types';
|
||||||
|
import BaseModelSelect from '../shared/BaseModelSelect';
|
||||||
|
import ModelVariantSelect from '../shared/ModelVariantSelect';
|
||||||
|
|
||||||
|
type AdvancedAddDiffusersProps = {
|
||||||
|
model_path?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AdvancedAddDiffusers(props: AdvancedAddDiffusersProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { model_path } = props;
|
||||||
|
|
||||||
|
const [addMainModel] = useAddMainModelsMutation();
|
||||||
|
|
||||||
|
const advancedAddDiffusersForm = useForm<DiffusersModelConfig>({
|
||||||
|
initialValues: {
|
||||||
|
model_name: model_path ? model_path.split('\\').splice(-1)[0] : '',
|
||||||
|
base_model: 'sd-1',
|
||||||
|
model_type: 'main',
|
||||||
|
path: model_path ? model_path : '',
|
||||||
|
description: '',
|
||||||
|
model_format: 'diffusers',
|
||||||
|
error: undefined,
|
||||||
|
vae: '',
|
||||||
|
variant: 'normal',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const advancedAddDiffusersFormHandler = (values: DiffusersModelConfig) => {
|
||||||
|
addMainModel({
|
||||||
|
body: values,
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.then((_) => {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: `Model Added: ${values.model_name}`,
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
advancedAddDiffusersForm.reset();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (error) {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: 'Model Add Failed',
|
||||||
|
status: 'error',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
onSubmit={advancedAddDiffusersForm.onSubmit((v) =>
|
||||||
|
advancedAddDiffusersFormHandler(v)
|
||||||
|
)}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
>
|
||||||
|
<Flex flexDirection="column" gap={2}>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
required
|
||||||
|
label="Model Name"
|
||||||
|
{...advancedAddDiffusersForm.getInputProps('model_name')}
|
||||||
|
/>
|
||||||
|
<BaseModelSelect
|
||||||
|
{...advancedAddDiffusersForm.getInputProps('base_model')}
|
||||||
|
/>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
required
|
||||||
|
label="Model Location"
|
||||||
|
placeholder="Provide the path to a local folder where your Diffusers Model is stored"
|
||||||
|
{...advancedAddDiffusersForm.getInputProps('path')}
|
||||||
|
/>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
label="Description"
|
||||||
|
{...advancedAddDiffusersForm.getInputProps('description')}
|
||||||
|
/>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
label="VAE Location"
|
||||||
|
{...advancedAddDiffusersForm.getInputProps('vae')}
|
||||||
|
/>
|
||||||
|
<ModelVariantSelect
|
||||||
|
{...advancedAddDiffusersForm.getInputProps('variant')}
|
||||||
|
/>
|
||||||
|
<IAIButton mt={2} type="submit">
|
||||||
|
{t('modelManager.addModel')}
|
||||||
|
</IAIButton>
|
||||||
|
</Flex>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { SelectItem } from '@mantine/core';
|
||||||
|
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import AdvancedAddCheckpoint from './AdvancedAddCheckpoint';
|
||||||
|
import AdvancedAddDiffusers from './AdvancedAddDiffusers';
|
||||||
|
|
||||||
|
export const advancedAddModeData: SelectItem[] = [
|
||||||
|
{ label: 'Diffusers', value: 'diffusers' },
|
||||||
|
{ label: 'Checkpoint / Safetensors', value: 'checkpoint' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export type ManualAddMode = 'diffusers' | 'checkpoint';
|
||||||
|
|
||||||
|
export default function AdvancedAddModels() {
|
||||||
|
const [advancedAddMode, setAdvancedAddMode] =
|
||||||
|
useState<ManualAddMode>('diffusers');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex flexDirection="column" gap={4} width="100%">
|
||||||
|
<IAIMantineSelect
|
||||||
|
label="Model Type"
|
||||||
|
value={advancedAddMode}
|
||||||
|
data={advancedAddModeData}
|
||||||
|
onChange={(v) => {
|
||||||
|
if (!v) return;
|
||||||
|
setAdvancedAddMode(v as ManualAddMode);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
p: 4,
|
||||||
|
borderRadius: 4,
|
||||||
|
bg: 'base.300',
|
||||||
|
_dark: {
|
||||||
|
bg: 'base.850',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{advancedAddMode === 'diffusers' && <AdvancedAddDiffusers />}
|
||||||
|
{advancedAddMode === 'checkpoint' && <AdvancedAddCheckpoint />}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,215 @@
|
|||||||
|
import { Flex, Text } from '@chakra-ui/react';
|
||||||
|
import { makeToast } from 'app/components/Toaster';
|
||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import IAIInput from 'common/components/IAIInput';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { difference, forEach, map, values } from 'lodash-es';
|
||||||
|
import { ChangeEvent, MouseEvent, useCallback, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import {
|
||||||
|
SearchFolderResponse,
|
||||||
|
useGetMainModelsQuery,
|
||||||
|
useGetModelsInFolderQuery,
|
||||||
|
useImportMainModelsMutation,
|
||||||
|
} from 'services/api/endpoints/models';
|
||||||
|
import { setAdvancedAddScanModel } from '../../store/modelManagerSlice';
|
||||||
|
|
||||||
|
export default function FoundModelsList() {
|
||||||
|
const searchFolder = useAppSelector(
|
||||||
|
(state: RootState) => state.modelmanager.searchFolder
|
||||||
|
);
|
||||||
|
const [nameFilter, setNameFilter] = useState<string>('');
|
||||||
|
|
||||||
|
// Get paths of models that are already installed
|
||||||
|
const { data: installedModels } = useGetMainModelsQuery();
|
||||||
|
|
||||||
|
// Get all model paths from a given directory
|
||||||
|
const { foundModels, notInstalledModels, filteredModels } =
|
||||||
|
useGetModelsInFolderQuery(
|
||||||
|
{
|
||||||
|
search_path: searchFolder ? searchFolder : '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selectFromResult: ({ data }) => {
|
||||||
|
const installedModelValues = values(installedModels?.entities);
|
||||||
|
const installedModelPaths = map(installedModelValues, 'path');
|
||||||
|
// Only select models those that aren't already installed to Invoke
|
||||||
|
const notInstalledModels = difference(data, installedModelPaths);
|
||||||
|
return {
|
||||||
|
foundModels: data,
|
||||||
|
notInstalledModels: notInstalledModels,
|
||||||
|
filteredModels: foundModelsFilter(notInstalledModels, nameFilter),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const [importMainModel, { isLoading }] = useImportMainModelsMutation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const quickAddHandler = useCallback(
|
||||||
|
(e: MouseEvent<HTMLButtonElement>) => {
|
||||||
|
const model_name = e.currentTarget.id.split('\\').splice(-1)[0];
|
||||||
|
importMainModel({
|
||||||
|
body: {
|
||||||
|
location: e.currentTarget.id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.then((_) => {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: `Added Model: ${model_name}`,
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (error) {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: 'Faile To Add Model',
|
||||||
|
status: 'error',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[dispatch, importMainModel]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSearchFilter = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setNameFilter(e.target.value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const renderFoundModels = () => {
|
||||||
|
if (!searchFolder) return;
|
||||||
|
|
||||||
|
if (!foundModels || foundModels.length === 0) {
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
w: 'full',
|
||||||
|
h: 'full',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
height: 96,
|
||||||
|
userSelect: 'none',
|
||||||
|
bg: 'base.200',
|
||||||
|
_dark: {
|
||||||
|
bg: 'base.900',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text variant="subtext">No Models Found</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: 2,
|
||||||
|
w: '100%',
|
||||||
|
minW: '50%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IAIInput
|
||||||
|
onChange={handleSearchFilter}
|
||||||
|
label={t('modelManager.search')}
|
||||||
|
/>
|
||||||
|
<Flex p={2} gap={2}>
|
||||||
|
<Text
|
||||||
|
sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
color: 'accent.500',
|
||||||
|
_dark: {
|
||||||
|
color: 'accent.200',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Found Models: {foundModels.length}
|
||||||
|
</Text>
|
||||||
|
<Text sx={{ fontWeight: 600 }}>
|
||||||
|
Not Installed: {notInstalledModels.length}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{filteredModels.map((model) => (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
p: 4,
|
||||||
|
gap: 4,
|
||||||
|
alignItems: 'center',
|
||||||
|
borderRadius: 4,
|
||||||
|
bg: 'base.200',
|
||||||
|
_dark: {
|
||||||
|
bg: 'base.800',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
key={model}
|
||||||
|
>
|
||||||
|
<Flex w="100%" sx={{ flexDirection: 'column', minW: '25%' }}>
|
||||||
|
<Text sx={{ fontWeight: 600 }}>
|
||||||
|
{model.split('\\').slice(-1)[0]}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
sx={{
|
||||||
|
fontSize: 'sm',
|
||||||
|
color: 'base.600',
|
||||||
|
_dark: {
|
||||||
|
color: 'base.400',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{model}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
<Flex gap={2}>
|
||||||
|
<IAIButton
|
||||||
|
id={model}
|
||||||
|
onClick={quickAddHandler}
|
||||||
|
isLoading={isLoading}
|
||||||
|
>
|
||||||
|
Quick Add
|
||||||
|
</IAIButton>
|
||||||
|
<IAIButton
|
||||||
|
onClick={() => dispatch(setAdvancedAddScanModel(model))}
|
||||||
|
isLoading={isLoading}
|
||||||
|
>
|
||||||
|
Advanced
|
||||||
|
</IAIButton>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return renderFoundModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
const foundModelsFilter = (
|
||||||
|
data: SearchFolderResponse | undefined,
|
||||||
|
nameFilter: string
|
||||||
|
) => {
|
||||||
|
const filteredModels: SearchFolderResponse = [];
|
||||||
|
forEach(data, (model) => {
|
||||||
|
if (!model) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model.includes(nameFilter)) {
|
||||||
|
filteredModels.push(model);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return filteredModels;
|
||||||
|
};
|
@ -0,0 +1,99 @@
|
|||||||
|
import { Box, Flex, Text } from '@chakra-ui/react';
|
||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { FaTimes } from 'react-icons/fa';
|
||||||
|
import { setAdvancedAddScanModel } from '../../store/modelManagerSlice';
|
||||||
|
import AdvancedAddCheckpoint from './AdvancedAddCheckpoint';
|
||||||
|
import AdvancedAddDiffusers from './AdvancedAddDiffusers';
|
||||||
|
import { ManualAddMode, advancedAddModeData } from './AdvancedAddModels';
|
||||||
|
|
||||||
|
export default function ScanAdvancedAddModels() {
|
||||||
|
const advancedAddScanModel = useAppSelector(
|
||||||
|
(state: RootState) => state.modelmanager.advancedAddScanModel
|
||||||
|
);
|
||||||
|
|
||||||
|
const [advancedAddMode, setAdvancedAddMode] =
|
||||||
|
useState<ManualAddMode>('diffusers');
|
||||||
|
|
||||||
|
const [isCheckpoint, setIsCheckpoint] = useState(
|
||||||
|
advancedAddScanModel &&
|
||||||
|
['.ckpt', '.safetensors', '.pth', '.pt'].some((ext) =>
|
||||||
|
advancedAddScanModel.endsWith(ext)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
isCheckpoint
|
||||||
|
? setAdvancedAddMode('checkpoint')
|
||||||
|
: setAdvancedAddMode('diffusers');
|
||||||
|
}, [setAdvancedAddMode, isCheckpoint]);
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
return (
|
||||||
|
advancedAddScanModel && (
|
||||||
|
<Box
|
||||||
|
as={motion.div}
|
||||||
|
initial={{ x: -100, opacity: 0 }}
|
||||||
|
animate={{ x: 0, opacity: 1, transition: { duration: 0.2 } }}
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
minWidth: '50%',
|
||||||
|
maxHeight: window.innerHeight - 330,
|
||||||
|
overflow: 'scroll',
|
||||||
|
p: 4,
|
||||||
|
gap: 4,
|
||||||
|
borderRadius: 4,
|
||||||
|
bg: 'base.200',
|
||||||
|
_dark: {
|
||||||
|
bg: 'base.800',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex justifyContent="space-between" alignItems="center">
|
||||||
|
<Text size="xl" fontWeight={600}>
|
||||||
|
{isCheckpoint || advancedAddMode === 'checkpoint'
|
||||||
|
? 'Add Checkpoint Model'
|
||||||
|
: 'Add Diffusers Model'}
|
||||||
|
</Text>
|
||||||
|
<IAIIconButton
|
||||||
|
icon={<FaTimes />}
|
||||||
|
aria-label="Close Advanced"
|
||||||
|
onClick={() => dispatch(setAdvancedAddScanModel(null))}
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
<IAIMantineSelect
|
||||||
|
label="Model Type"
|
||||||
|
value={advancedAddMode}
|
||||||
|
data={advancedAddModeData}
|
||||||
|
onChange={(v) => {
|
||||||
|
if (!v) return;
|
||||||
|
setAdvancedAddMode(v as ManualAddMode);
|
||||||
|
if (v === 'checkpoint') {
|
||||||
|
setIsCheckpoint(true);
|
||||||
|
} else {
|
||||||
|
setIsCheckpoint(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{isCheckpoint ? (
|
||||||
|
<AdvancedAddCheckpoint
|
||||||
|
key={advancedAddScanModel}
|
||||||
|
model_path={advancedAddScanModel}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<AdvancedAddDiffusers
|
||||||
|
key={advancedAddScanModel}
|
||||||
|
model_path={advancedAddScanModel}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import FoundModelsList from './FoundModelsList';
|
||||||
|
import ScanAdvancedAddModels from './ScanAdvancedAddModels';
|
||||||
|
import SearchFolderForm from './SearchFolderForm';
|
||||||
|
|
||||||
|
export default function ScanModels() {
|
||||||
|
return (
|
||||||
|
<Flex flexDirection="column" w="100%" gap={4}>
|
||||||
|
<SearchFolderForm />
|
||||||
|
<Flex gap={4}>
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
maxHeight: window.innerHeight - 330,
|
||||||
|
overflow: 'scroll',
|
||||||
|
gap: 4,
|
||||||
|
w: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FoundModelsList />
|
||||||
|
</Flex>
|
||||||
|
<ScanAdvancedAddModels />
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
import { Flex, Text } from '@chakra-ui/react';
|
||||||
|
import { useForm } from '@mantine/form';
|
||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
import IAIInput from 'common/components/IAIInput';
|
||||||
|
import { memo, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaSearch, FaSync, FaTrash } from 'react-icons/fa';
|
||||||
|
import {
|
||||||
|
setAdvancedAddScanModel,
|
||||||
|
setSearchFolder,
|
||||||
|
} from '../../store/modelManagerSlice';
|
||||||
|
|
||||||
|
type SearchFolderForm = {
|
||||||
|
folder: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function SearchFolderForm() {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const searchFolder = useAppSelector(
|
||||||
|
(state: RootState) => state.modelmanager.searchFolder
|
||||||
|
);
|
||||||
|
|
||||||
|
const searchFolderForm = useForm<SearchFolderForm>({
|
||||||
|
initialValues: {
|
||||||
|
folder: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const searchFolderFormSubmitHandler = useCallback(
|
||||||
|
(values: SearchFolderForm) => {
|
||||||
|
dispatch(setSearchFolder(values.folder));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
onSubmit={searchFolderForm.onSubmit((values) =>
|
||||||
|
searchFolderFormSubmitHandler(values)
|
||||||
|
)}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
w: '100%',
|
||||||
|
gap: 2,
|
||||||
|
p: 4,
|
||||||
|
borderRadius: 4,
|
||||||
|
background: 'base.300',
|
||||||
|
alignItems: 'center',
|
||||||
|
_dark: {
|
||||||
|
background: 'base.800',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex w="100%" alignItems="center" gap={4} minH={12}>
|
||||||
|
<Text
|
||||||
|
sx={{
|
||||||
|
fontWeight: 600,
|
||||||
|
color: 'base.700',
|
||||||
|
minW: 'max-content',
|
||||||
|
_dark: { color: 'base.300' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Search Folder
|
||||||
|
</Text>
|
||||||
|
{!searchFolder ? (
|
||||||
|
<IAIInput
|
||||||
|
w="100%"
|
||||||
|
size="md"
|
||||||
|
{...searchFolderForm.getInputProps('folder')}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
w: '100%',
|
||||||
|
p: 2,
|
||||||
|
px: 4,
|
||||||
|
bg: 'base.200',
|
||||||
|
borderRadius: 4,
|
||||||
|
_dark: { bg: 'base.700' },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{searchFolder}
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex gap={2}>
|
||||||
|
<IAIIconButton
|
||||||
|
aria-label={t('modelManager.scanAgain')}
|
||||||
|
tooltip={t('modelManager.scanAgain')}
|
||||||
|
icon={!searchFolder ? <FaSearch /> : <FaSync />}
|
||||||
|
fontSize={18}
|
||||||
|
size="sm"
|
||||||
|
type="submit"
|
||||||
|
/>
|
||||||
|
<IAIIconButton
|
||||||
|
aria-label={t('modelManager.clearCheckpointFolder')}
|
||||||
|
tooltip={t('modelManager.clearCheckpointFolder')}
|
||||||
|
icon={<FaTrash />}
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
dispatch(setSearchFolder(null));
|
||||||
|
dispatch(setAdvancedAddScanModel(null));
|
||||||
|
}}
|
||||||
|
isDisabled={!searchFolder}
|
||||||
|
colorScheme="red"
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(SearchFolderForm);
|
@ -0,0 +1,108 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
// import { addNewModel } from 'app/socketio/actions';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { SelectItem } from '@mantine/core';
|
||||||
|
import { useForm } from '@mantine/form';
|
||||||
|
import { makeToast } from 'app/components/Toaster';
|
||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
|
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { useImportMainModelsMutation } from 'services/api/endpoints/models';
|
||||||
|
|
||||||
|
const predictionSelectData: SelectItem[] = [
|
||||||
|
{ label: 'None', value: 'none' },
|
||||||
|
{ label: 'v_prediction', value: 'v_prediction' },
|
||||||
|
{ label: 'epsilon', value: 'epsilon' },
|
||||||
|
{ label: 'sample', value: 'sample' },
|
||||||
|
];
|
||||||
|
|
||||||
|
type ExtendedImportModelConfig = {
|
||||||
|
location: string;
|
||||||
|
prediction_type?: 'v_prediction' | 'epsilon' | 'sample' | 'none' | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function SimpleAddModels() {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const isProcessing = useAppSelector(
|
||||||
|
(state: RootState) => state.system.isProcessing
|
||||||
|
);
|
||||||
|
|
||||||
|
const [importMainModel, { isLoading }] = useImportMainModelsMutation();
|
||||||
|
|
||||||
|
const addModelForm = useForm<ExtendedImportModelConfig>({
|
||||||
|
initialValues: {
|
||||||
|
location: '',
|
||||||
|
prediction_type: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleAddModelSubmit = (values: ExtendedImportModelConfig) => {
|
||||||
|
const importModelResponseBody = {
|
||||||
|
location: values.location,
|
||||||
|
prediction_type:
|
||||||
|
values.prediction_type === 'none' ? undefined : values.prediction_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
importMainModel({ body: importModelResponseBody })
|
||||||
|
.unwrap()
|
||||||
|
.then((_) => {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: 'Model Added',
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
addModelForm.reset();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: `${error.data.detail} `,
|
||||||
|
status: 'error',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
onSubmit={addModelForm.onSubmit((v) => handleAddModelSubmit(v))}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
>
|
||||||
|
<Flex flexDirection="column" width="100%" gap={4}>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
label="Model Location"
|
||||||
|
placeholder="Provide a path to a local Diffusers model, local checkpoint / safetensors model or a HuggingFace Repo ID"
|
||||||
|
w="100%"
|
||||||
|
{...addModelForm.getInputProps('location')}
|
||||||
|
/>
|
||||||
|
<IAIMantineSelect
|
||||||
|
label="Prediction Type (for Stable Diffusion 2.x Models only)"
|
||||||
|
data={predictionSelectData}
|
||||||
|
defaultValue="none"
|
||||||
|
{...addModelForm.getInputProps('prediction_type')}
|
||||||
|
/>
|
||||||
|
<IAIButton
|
||||||
|
type="submit"
|
||||||
|
isLoading={isLoading}
|
||||||
|
isDisabled={isLoading || isProcessing}
|
||||||
|
>
|
||||||
|
{t('modelManager.addModel')}
|
||||||
|
</IAIButton>
|
||||||
|
</Flex>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
import { ButtonGroup, Flex } from '@chakra-ui/react';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import AddModels from './AddModelsPanel/AddModels';
|
||||||
|
import ScanModels from './AddModelsPanel/ScanModels';
|
||||||
|
|
||||||
|
type AddModelTabs = 'add' | 'scan';
|
||||||
|
|
||||||
|
export default function ImportModelsPanel() {
|
||||||
|
const [addModelTab, setAddModelTab] = useState<AddModelTabs>('add');
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex flexDirection="column" gap={4}>
|
||||||
|
<ButtonGroup isAttached>
|
||||||
|
<IAIButton
|
||||||
|
onClick={() => setAddModelTab('add')}
|
||||||
|
isChecked={addModelTab == 'add'}
|
||||||
|
size="sm"
|
||||||
|
width="100%"
|
||||||
|
>
|
||||||
|
{t('modelManager.addModel')}
|
||||||
|
</IAIButton>
|
||||||
|
<IAIButton
|
||||||
|
onClick={() => setAddModelTab('scan')}
|
||||||
|
isChecked={addModelTab == 'scan'}
|
||||||
|
size="sm"
|
||||||
|
width="100%"
|
||||||
|
>
|
||||||
|
{t('modelManager.scanForModels')}
|
||||||
|
</IAIButton>
|
||||||
|
</ButtonGroup>
|
||||||
|
|
||||||
|
{addModelTab == 'add' && <AddModels />}
|
||||||
|
{addModelTab == 'scan' && <ScanModels />}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
@ -125,9 +125,9 @@ export default function MergeModelsPanel() {
|
|||||||
mergedModelName !== '' ? mergedModelName : models_names.join('-'),
|
mergedModelName !== '' ? mergedModelName : models_names.join('-'),
|
||||||
alpha: modelMergeAlpha,
|
alpha: modelMergeAlpha,
|
||||||
interp: modelMergeInterp,
|
interp: modelMergeInterp,
|
||||||
// model_merge_save_path:
|
|
||||||
// modelMergeSaveLocType === 'root' ? null : modelMergeCustomSaveLoc,
|
|
||||||
force: modelMergeForce,
|
force: modelMergeForce,
|
||||||
|
merge_dest_directory:
|
||||||
|
modelMergeSaveLocType === 'root' ? undefined : modelMergeCustomSaveLoc,
|
||||||
};
|
};
|
||||||
|
|
||||||
mergeModels({
|
mergeModels({
|
||||||
@ -288,7 +288,7 @@ export default function MergeModelsPanel() {
|
|||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
{/* <Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
padding: 4,
|
padding: 4,
|
||||||
@ -324,7 +324,7 @@ export default function MergeModelsPanel() {
|
|||||||
onChange={(e) => setModelMergeCustomSaveLoc(e.target.value)}
|
onChange={(e) => setModelMergeCustomSaveLoc(e.target.value)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Flex> */}
|
</Flex>
|
||||||
|
|
||||||
<IAISimpleCheckbox
|
<IAISimpleCheckbox
|
||||||
label={t('modelManager.ignoreMismatch')}
|
label={t('modelManager.ignoreMismatch')}
|
||||||
|
@ -4,30 +4,23 @@ import { makeToast } from 'app/components/Toaster';
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
||||||
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
|
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
|
||||||
import { selectIsBusy } from 'features/system/store/systemSelectors';
|
import { selectIsBusy } from 'features/system/store/systemSelectors';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { useCallback } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
CheckpointModelConfigEntity,
|
CheckpointModelConfigEntity,
|
||||||
|
useGetCheckpointConfigsQuery,
|
||||||
useUpdateMainModelsMutation,
|
useUpdateMainModelsMutation,
|
||||||
} from 'services/api/endpoints/models';
|
} from 'services/api/endpoints/models';
|
||||||
import { CheckpointModelConfig } from 'services/api/types';
|
import { CheckpointModelConfig } from 'services/api/types';
|
||||||
|
import BaseModelSelect from '../shared/BaseModelSelect';
|
||||||
|
import CheckpointConfigsSelect from '../shared/CheckpointConfigsSelect';
|
||||||
|
import ModelVariantSelect from '../shared/ModelVariantSelect';
|
||||||
import ModelConvert from './ModelConvert';
|
import ModelConvert from './ModelConvert';
|
||||||
|
|
||||||
const baseModelSelectData = [
|
|
||||||
{ value: 'sd-1', label: MODEL_TYPE_MAP['sd-1'] },
|
|
||||||
{ value: 'sd-2', label: MODEL_TYPE_MAP['sd-2'] },
|
|
||||||
];
|
|
||||||
|
|
||||||
const variantSelectData = [
|
|
||||||
{ value: 'normal', label: 'Normal' },
|
|
||||||
{ value: 'inpaint', label: 'Inpaint' },
|
|
||||||
{ value: 'depth', label: 'Depth' },
|
|
||||||
];
|
|
||||||
|
|
||||||
type CheckpointModelEditProps = {
|
type CheckpointModelEditProps = {
|
||||||
model: CheckpointModelConfigEntity;
|
model: CheckpointModelConfigEntity;
|
||||||
};
|
};
|
||||||
@ -38,6 +31,15 @@ export default function CheckpointModelEdit(props: CheckpointModelEditProps) {
|
|||||||
const { model } = props;
|
const { model } = props;
|
||||||
|
|
||||||
const [updateMainModel, { isLoading }] = useUpdateMainModelsMutation();
|
const [updateMainModel, { isLoading }] = useUpdateMainModelsMutation();
|
||||||
|
const { data: availableCheckpointConfigs } = useGetCheckpointConfigsQuery();
|
||||||
|
|
||||||
|
const [useCustomConfig, setUseCustomConfig] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!availableCheckpointConfigs?.includes(model.config)) {
|
||||||
|
setUseCustomConfig(true);
|
||||||
|
}
|
||||||
|
}, [availableCheckpointConfigs, model.config]);
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -80,7 +82,7 @@ export default function CheckpointModelEdit(props: CheckpointModelEditProps) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((_) => {
|
||||||
checkpointEditForm.reset();
|
checkpointEditForm.reset();
|
||||||
dispatch(
|
dispatch(
|
||||||
addToast(
|
addToast(
|
||||||
@ -128,21 +130,24 @@ export default function CheckpointModelEdit(props: CheckpointModelEditProps) {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Flex flexDirection="column" overflowY="scroll" gap={4}>
|
<Flex flexDirection="column" overflowY="scroll" gap={4}>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
label={t('modelManager.name')}
|
||||||
|
{...checkpointEditForm.getInputProps('model_name')}
|
||||||
|
/>
|
||||||
<IAIMantineTextInput
|
<IAIMantineTextInput
|
||||||
label={t('modelManager.description')}
|
label={t('modelManager.description')}
|
||||||
{...checkpointEditForm.getInputProps('description')}
|
{...checkpointEditForm.getInputProps('description')}
|
||||||
/>
|
/>
|
||||||
<IAIMantineSelect
|
<BaseModelSelect
|
||||||
label={t('modelManager.baseModel')}
|
required
|
||||||
data={baseModelSelectData}
|
|
||||||
{...checkpointEditForm.getInputProps('base_model')}
|
{...checkpointEditForm.getInputProps('base_model')}
|
||||||
/>
|
/>
|
||||||
<IAIMantineSelect
|
<ModelVariantSelect
|
||||||
label={t('modelManager.variant')}
|
required
|
||||||
data={variantSelectData}
|
|
||||||
{...checkpointEditForm.getInputProps('variant')}
|
{...checkpointEditForm.getInputProps('variant')}
|
||||||
/>
|
/>
|
||||||
<IAIMantineTextInput
|
<IAIMantineTextInput
|
||||||
|
required
|
||||||
label={t('modelManager.modelLocation')}
|
label={t('modelManager.modelLocation')}
|
||||||
{...checkpointEditForm.getInputProps('path')}
|
{...checkpointEditForm.getInputProps('path')}
|
||||||
/>
|
/>
|
||||||
@ -150,10 +155,27 @@ export default function CheckpointModelEdit(props: CheckpointModelEditProps) {
|
|||||||
label={t('modelManager.vaeLocation')}
|
label={t('modelManager.vaeLocation')}
|
||||||
{...checkpointEditForm.getInputProps('vae')}
|
{...checkpointEditForm.getInputProps('vae')}
|
||||||
/>
|
/>
|
||||||
<IAIMantineTextInput
|
|
||||||
label={t('modelManager.config')}
|
<Flex flexDirection="column" gap={2}>
|
||||||
{...checkpointEditForm.getInputProps('config')}
|
{!useCustomConfig ? (
|
||||||
/>
|
<CheckpointConfigsSelect
|
||||||
|
required
|
||||||
|
{...checkpointEditForm.getInputProps('config')}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<IAIMantineTextInput
|
||||||
|
required
|
||||||
|
label={t('modelManager.config')}
|
||||||
|
{...checkpointEditForm.getInputProps('config')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<IAISimpleCheckbox
|
||||||
|
isChecked={useCustomConfig}
|
||||||
|
onChange={() => setUseCustomConfig(!useCustomConfig)}
|
||||||
|
label="Use Custom Config"
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<IAIButton
|
<IAIButton
|
||||||
type="submit"
|
type="submit"
|
||||||
isDisabled={isBusy || isLoading}
|
isDisabled={isBusy || isLoading}
|
||||||
|
@ -4,7 +4,6 @@ import { makeToast } from 'app/components/Toaster';
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
|
||||||
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
|
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
|
||||||
import { selectIsBusy } from 'features/system/store/systemSelectors';
|
import { selectIsBusy } from 'features/system/store/systemSelectors';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
@ -15,22 +14,13 @@ import {
|
|||||||
useUpdateMainModelsMutation,
|
useUpdateMainModelsMutation,
|
||||||
} from 'services/api/endpoints/models';
|
} from 'services/api/endpoints/models';
|
||||||
import { DiffusersModelConfig } from 'services/api/types';
|
import { DiffusersModelConfig } from 'services/api/types';
|
||||||
|
import BaseModelSelect from '../shared/BaseModelSelect';
|
||||||
|
import ModelVariantSelect from '../shared/ModelVariantSelect';
|
||||||
|
|
||||||
type DiffusersModelEditProps = {
|
type DiffusersModelEditProps = {
|
||||||
model: DiffusersModelConfigEntity;
|
model: DiffusersModelConfigEntity;
|
||||||
};
|
};
|
||||||
|
|
||||||
const baseModelSelectData = [
|
|
||||||
{ value: 'sd-1', label: MODEL_TYPE_MAP['sd-1'] },
|
|
||||||
{ value: 'sd-2', label: MODEL_TYPE_MAP['sd-2'] },
|
|
||||||
];
|
|
||||||
|
|
||||||
const variantSelectData = [
|
|
||||||
{ value: 'normal', label: 'Normal' },
|
|
||||||
{ value: 'inpaint', label: 'Inpaint' },
|
|
||||||
{ value: 'depth', label: 'Depth' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function DiffusersModelEdit(props: DiffusersModelEditProps) {
|
export default function DiffusersModelEdit(props: DiffusersModelEditProps) {
|
||||||
const isBusy = useAppSelector(selectIsBusy);
|
const isBusy = useAppSelector(selectIsBusy);
|
||||||
|
|
||||||
@ -65,6 +55,7 @@ export default function DiffusersModelEdit(props: DiffusersModelEditProps) {
|
|||||||
model_name: model.model_name,
|
model_name: model.model_name,
|
||||||
body: values,
|
body: values,
|
||||||
};
|
};
|
||||||
|
|
||||||
updateMainModel(responseBody)
|
updateMainModel(responseBody)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.then((payload) => {
|
.then((payload) => {
|
||||||
@ -78,7 +69,7 @@ export default function DiffusersModelEdit(props: DiffusersModelEditProps) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((_) => {
|
||||||
diffusersEditForm.reset();
|
diffusersEditForm.reset();
|
||||||
dispatch(
|
dispatch(
|
||||||
addToast(
|
addToast(
|
||||||
@ -118,21 +109,24 @@ export default function DiffusersModelEdit(props: DiffusersModelEditProps) {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Flex flexDirection="column" overflowY="scroll" gap={4}>
|
<Flex flexDirection="column" overflowY="scroll" gap={4}>
|
||||||
|
<IAIMantineTextInput
|
||||||
|
label={t('modelManager.name')}
|
||||||
|
{...diffusersEditForm.getInputProps('model_name')}
|
||||||
|
/>
|
||||||
<IAIMantineTextInput
|
<IAIMantineTextInput
|
||||||
label={t('modelManager.description')}
|
label={t('modelManager.description')}
|
||||||
{...diffusersEditForm.getInputProps('description')}
|
{...diffusersEditForm.getInputProps('description')}
|
||||||
/>
|
/>
|
||||||
<IAIMantineSelect
|
<BaseModelSelect
|
||||||
label={t('modelManager.baseModel')}
|
required
|
||||||
data={baseModelSelectData}
|
|
||||||
{...diffusersEditForm.getInputProps('base_model')}
|
{...diffusersEditForm.getInputProps('base_model')}
|
||||||
/>
|
/>
|
||||||
<IAIMantineSelect
|
<ModelVariantSelect
|
||||||
label={t('modelManager.variant')}
|
required
|
||||||
data={variantSelectData}
|
|
||||||
{...diffusersEditForm.getInputProps('variant')}
|
{...diffusersEditForm.getInputProps('variant')}
|
||||||
/>
|
/>
|
||||||
<IAIMantineTextInput
|
<IAIMantineTextInput
|
||||||
|
required
|
||||||
label={t('modelManager.modelLocation')}
|
label={t('modelManager.modelLocation')}
|
||||||
{...diffusersEditForm.getInputProps('path')}
|
{...diffusersEditForm.getInputProps('path')}
|
||||||
/>
|
/>
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
import { Flex, ListItem, Text, UnorderedList } from '@chakra-ui/react';
|
import {
|
||||||
// import { convertToDiffusers } from 'app/socketio/actions';
|
Flex,
|
||||||
|
ListItem,
|
||||||
|
Radio,
|
||||||
|
RadioGroup,
|
||||||
|
Text,
|
||||||
|
Tooltip,
|
||||||
|
UnorderedList,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'app/components/Toaster';
|
||||||
|
// import { convertToDiffusers } from 'app/socketio/actions';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import IAIInput from 'common/components/IAIInput';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -15,6 +24,8 @@ interface ModelConvertProps {
|
|||||||
model: CheckpointModelConfig;
|
model: CheckpointModelConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SaveLocation = 'InvokeAIRoot' | 'Custom';
|
||||||
|
|
||||||
export default function ModelConvert(props: ModelConvertProps) {
|
export default function ModelConvert(props: ModelConvertProps) {
|
||||||
const { model } = props;
|
const { model } = props;
|
||||||
|
|
||||||
@ -23,22 +34,51 @@ export default function ModelConvert(props: ModelConvertProps) {
|
|||||||
|
|
||||||
const [convertModel, { isLoading }] = useConvertMainModelsMutation();
|
const [convertModel, { isLoading }] = useConvertMainModelsMutation();
|
||||||
|
|
||||||
const [saveLocation, setSaveLocation] = useState<string>('same');
|
const [saveLocation, setSaveLocation] =
|
||||||
|
useState<SaveLocation>('InvokeAIRoot');
|
||||||
const [customSaveLocation, setCustomSaveLocation] = useState<string>('');
|
const [customSaveLocation, setCustomSaveLocation] = useState<string>('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSaveLocation('same');
|
setSaveLocation('InvokeAIRoot');
|
||||||
}, [model]);
|
}, [model]);
|
||||||
|
|
||||||
const modelConvertCancelHandler = () => {
|
const modelConvertCancelHandler = () => {
|
||||||
setSaveLocation('same');
|
setSaveLocation('InvokeAIRoot');
|
||||||
};
|
};
|
||||||
|
|
||||||
const modelConvertHandler = () => {
|
const modelConvertHandler = () => {
|
||||||
const responseBody = {
|
const responseBody = {
|
||||||
base_model: model.base_model,
|
base_model: model.base_model,
|
||||||
model_name: model.model_name,
|
model_name: model.model_name,
|
||||||
|
params: {
|
||||||
|
convert_dest_directory:
|
||||||
|
saveLocation === 'Custom' ? customSaveLocation : undefined,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (saveLocation === 'Custom' && customSaveLocation === '') {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: t('modelManager.noCustomLocationProvided'),
|
||||||
|
status: 'error',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: `${t('modelManager.convertingModelBegin')}: ${
|
||||||
|
model.model_name
|
||||||
|
}`,
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
convertModel(responseBody)
|
convertModel(responseBody)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.then((_) => {
|
.then((_) => {
|
||||||
@ -94,35 +134,30 @@ export default function ModelConvert(props: ModelConvertProps) {
|
|||||||
<Text>{t('modelManager.convertToDiffusersHelpText6')}</Text>
|
<Text>{t('modelManager.convertToDiffusersHelpText6')}</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
{/* <Flex flexDir="column" gap={4}>
|
<Flex flexDir="column" gap={2}>
|
||||||
<Flex marginTop={4} flexDir="column" gap={2}>
|
<Flex marginTop={4} flexDir="column" gap={2}>
|
||||||
<Text fontWeight="600">
|
<Text fontWeight="600">
|
||||||
{t('modelManager.convertToDiffusersSaveLocation')}
|
{t('modelManager.convertToDiffusersSaveLocation')}
|
||||||
</Text>
|
</Text>
|
||||||
<RadioGroup value={saveLocation} onChange={(v) => setSaveLocation(v)}>
|
<RadioGroup
|
||||||
|
value={saveLocation}
|
||||||
|
onChange={(v) => setSaveLocation(v as SaveLocation)}
|
||||||
|
>
|
||||||
<Flex gap={4}>
|
<Flex gap={4}>
|
||||||
<Radio value="same">
|
<Radio value="InvokeAIRoot">
|
||||||
<Tooltip label="Save converted model in the same folder">
|
|
||||||
{t('modelManager.sameFolder')}
|
|
||||||
</Tooltip>
|
|
||||||
</Radio>
|
|
||||||
|
|
||||||
<Radio value="root">
|
|
||||||
<Tooltip label="Save converted model in the InvokeAI root folder">
|
<Tooltip label="Save converted model in the InvokeAI root folder">
|
||||||
{t('modelManager.invokeRoot')}
|
{t('modelManager.invokeRoot')}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Radio>
|
</Radio>
|
||||||
|
<Radio value="Custom">
|
||||||
<Radio value="custom">
|
|
||||||
<Tooltip label="Save converted model in a custom folder">
|
<Tooltip label="Save converted model in a custom folder">
|
||||||
{t('modelManager.custom')}
|
{t('modelManager.custom')}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Radio>
|
</Radio>
|
||||||
</Flex>
|
</Flex>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
</Flex> */}
|
</Flex>
|
||||||
|
{saveLocation === 'Custom' && (
|
||||||
{/* {saveLocation === 'custom' && (
|
|
||||||
<Flex flexDirection="column" rowGap={2}>
|
<Flex flexDirection="column" rowGap={2}>
|
||||||
<Text fontWeight="500" fontSize="sm" variant="subtext">
|
<Text fontWeight="500" fontSize="sm" variant="subtext">
|
||||||
{t('modelManager.customSaveLocation')}
|
{t('modelManager.customSaveLocation')}
|
||||||
@ -130,13 +165,13 @@ export default function ModelConvert(props: ModelConvertProps) {
|
|||||||
<IAIInput
|
<IAIInput
|
||||||
value={customSaveLocation}
|
value={customSaveLocation}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (e.target.value !== '')
|
setCustomSaveLocation(e.target.value);
|
||||||
setCustomSaveLocation(e.target.value);
|
|
||||||
}}
|
}}
|
||||||
width="full"
|
width="full"
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
)} */}
|
)}
|
||||||
|
</Flex>
|
||||||
</IAIAlertDialog>
|
</IAIAlertDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { DeleteIcon } from '@chakra-ui/icons';
|
import { DeleteIcon } from '@chakra-ui/icons';
|
||||||
import { Flex, Text, Tooltip } from '@chakra-ui/react';
|
import { Flex, Text, Tooltip } from '@chakra-ui/react';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { makeToast } from 'app/components/Toaster';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import { selectIsBusy } from 'features/system/store/systemSelectors';
|
import { selectIsBusy } from 'features/system/store/systemSelectors';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
@ -21,6 +23,7 @@ type ModelListItemProps = {
|
|||||||
export default function ModelListItem(props: ModelListItemProps) {
|
export default function ModelListItem(props: ModelListItemProps) {
|
||||||
const isBusy = useAppSelector(selectIsBusy);
|
const isBusy = useAppSelector(selectIsBusy);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
const [deleteMainModel] = useDeleteMainModelsMutation();
|
const [deleteMainModel] = useDeleteMainModelsMutation();
|
||||||
|
|
||||||
const { model, isSelected, setSelectedModelId } = props;
|
const { model, isSelected, setSelectedModelId } = props;
|
||||||
@ -30,9 +33,34 @@ export default function ModelListItem(props: ModelListItemProps) {
|
|||||||
}, [model.id, setSelectedModelId]);
|
}, [model.id, setSelectedModelId]);
|
||||||
|
|
||||||
const handleModelDelete = useCallback(() => {
|
const handleModelDelete = useCallback(() => {
|
||||||
deleteMainModel(model);
|
deleteMainModel(model)
|
||||||
|
.unwrap()
|
||||||
|
.then((_) => {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: `${t('modelManager.modelDeleted')}: ${model.model_name}`,
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (error) {
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: `${t('modelManager.modelDeleteFailed')}: ${
|
||||||
|
model.model_name
|
||||||
|
}`,
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
setSelectedModelId(undefined);
|
setSelectedModelId(undefined);
|
||||||
}, [deleteMainModel, model, setSelectedModelId]);
|
}, [deleteMainModel, model, setSelectedModelId, dispatch, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex sx={{ gap: 2, alignItems: 'center', w: 'full' }}>
|
<Flex sx={{ gap: 2, alignItems: 'center', w: 'full' }}>
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
import IAIMantineSelect, {
|
||||||
|
IAISelectDataType,
|
||||||
|
IAISelectProps,
|
||||||
|
} from 'common/components/IAIMantineSelect';
|
||||||
|
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const baseModelSelectData: IAISelectDataType[] = [
|
||||||
|
{ value: 'sd-1', label: MODEL_TYPE_MAP['sd-1'] },
|
||||||
|
{ value: 'sd-2', label: MODEL_TYPE_MAP['sd-2'] },
|
||||||
|
];
|
||||||
|
|
||||||
|
type BaseModelSelectProps = Omit<IAISelectProps, 'data'>;
|
||||||
|
|
||||||
|
export default function BaseModelSelect(props: BaseModelSelectProps) {
|
||||||
|
const { ...rest } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAIMantineSelect
|
||||||
|
label={t('modelManager.baseModel')}
|
||||||
|
data={baseModelSelectData}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import IAIMantineSelect, {
|
||||||
|
IAISelectProps,
|
||||||
|
} from 'common/components/IAIMantineSelect';
|
||||||
|
import { useGetCheckpointConfigsQuery } from 'services/api/endpoints/models';
|
||||||
|
|
||||||
|
type CheckpointConfigSelectProps = Omit<IAISelectProps, 'data'>;
|
||||||
|
|
||||||
|
export default function CheckpointConfigsSelect(
|
||||||
|
props: CheckpointConfigSelectProps
|
||||||
|
) {
|
||||||
|
const { data: availableCheckpointConfigs } = useGetCheckpointConfigsQuery();
|
||||||
|
const { ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAIMantineSelect
|
||||||
|
label="Config File"
|
||||||
|
placeholder="Select A Config File"
|
||||||
|
data={availableCheckpointConfigs ? availableCheckpointConfigs : []}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
import IAIMantineSelect, {
|
||||||
|
IAISelectDataType,
|
||||||
|
IAISelectProps,
|
||||||
|
} from 'common/components/IAIMantineSelect';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const variantSelectData: IAISelectDataType[] = [
|
||||||
|
{ value: 'normal', label: 'Normal' },
|
||||||
|
{ value: 'inpaint', label: 'Inpaint' },
|
||||||
|
{ value: 'depth', label: 'Depth' },
|
||||||
|
];
|
||||||
|
|
||||||
|
type VariantSelectProps = Omit<IAISelectProps, 'data'>;
|
||||||
|
|
||||||
|
export default function ModelVariantSelect(props: VariantSelectProps) {
|
||||||
|
const { ...rest } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAIMantineSelect
|
||||||
|
label={t('modelManager.variant')}
|
||||||
|
data={variantSelectData}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -1,7 +1,5 @@
|
|||||||
import { SchedulerParam } from 'features/parameters/types/parameterSchemas';
|
import { SchedulerParam } from 'features/parameters/types/parameterSchemas';
|
||||||
|
|
||||||
export type AddNewModelType = 'ckpt' | 'diffusers' | null;
|
|
||||||
|
|
||||||
export type Coordinates = {
|
export type Coordinates = {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
@ -22,7 +20,6 @@ export interface UIState {
|
|||||||
shouldUseCanvasBetaLayout: boolean;
|
shouldUseCanvasBetaLayout: boolean;
|
||||||
shouldShowExistingModelsInSearch: boolean;
|
shouldShowExistingModelsInSearch: boolean;
|
||||||
shouldUseSliders: boolean;
|
shouldUseSliders: boolean;
|
||||||
addNewModelUIOption: AddNewModelType;
|
|
||||||
shouldHidePreview: boolean;
|
shouldHidePreview: boolean;
|
||||||
shouldPinGallery: boolean;
|
shouldPinGallery: boolean;
|
||||||
shouldShowGallery: boolean;
|
shouldShowGallery: boolean;
|
||||||
|
@ -5,7 +5,9 @@ import {
|
|||||||
BaseModelType,
|
BaseModelType,
|
||||||
CheckpointModelConfig,
|
CheckpointModelConfig,
|
||||||
ControlNetModelConfig,
|
ControlNetModelConfig,
|
||||||
|
ConvertModelConfig,
|
||||||
DiffusersModelConfig,
|
DiffusersModelConfig,
|
||||||
|
ImportModelConfig,
|
||||||
LoRAModelConfig,
|
LoRAModelConfig,
|
||||||
MainModelConfig,
|
MainModelConfig,
|
||||||
MergeModelConfig,
|
MergeModelConfig,
|
||||||
@ -13,8 +15,9 @@ import {
|
|||||||
VaeModelConfig,
|
VaeModelConfig,
|
||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
|
|
||||||
|
import queryString from 'query-string';
|
||||||
import { ApiFullTagDescription, LIST_TAG, api } from '..';
|
import { ApiFullTagDescription, LIST_TAG, api } from '..';
|
||||||
import { paths } from '../schema';
|
import { operations, paths } from '../schema';
|
||||||
|
|
||||||
export type DiffusersModelConfigEntity = DiffusersModelConfig & { id: string };
|
export type DiffusersModelConfigEntity = DiffusersModelConfig & { id: string };
|
||||||
export type CheckpointModelConfigEntity = CheckpointModelConfig & {
|
export type CheckpointModelConfigEntity = CheckpointModelConfig & {
|
||||||
@ -62,6 +65,7 @@ type DeleteMainModelResponse = void;
|
|||||||
type ConvertMainModelArg = {
|
type ConvertMainModelArg = {
|
||||||
base_model: BaseModelType;
|
base_model: BaseModelType;
|
||||||
model_name: string;
|
model_name: string;
|
||||||
|
params: ConvertModelConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ConvertMainModelResponse =
|
type ConvertMainModelResponse =
|
||||||
@ -75,6 +79,28 @@ type MergeMainModelArg = {
|
|||||||
type MergeMainModelResponse =
|
type MergeMainModelResponse =
|
||||||
paths['/api/v1/models/merge/{base_model}']['put']['responses']['200']['content']['application/json'];
|
paths['/api/v1/models/merge/{base_model}']['put']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
type ImportMainModelArg = {
|
||||||
|
body: ImportModelConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ImportMainModelResponse =
|
||||||
|
paths['/api/v1/models/import']['post']['responses']['201']['content']['application/json'];
|
||||||
|
|
||||||
|
type AddMainModelArg = {
|
||||||
|
body: MainModelConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
type AddMainModelResponse =
|
||||||
|
paths['/api/v1/models/add']['post']['responses']['201']['content']['application/json'];
|
||||||
|
|
||||||
|
export type SearchFolderResponse =
|
||||||
|
paths['/api/v1/models/search']['get']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
type CheckpointConfigsResponse =
|
||||||
|
paths['/api/v1/models/ckpt_confs']['get']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
type SearchFolderArg = operations['search_for_models']['parameters']['query'];
|
||||||
|
|
||||||
const mainModelsAdapter = createEntityAdapter<MainModelConfigEntity>({
|
const mainModelsAdapter = createEntityAdapter<MainModelConfigEntity>({
|
||||||
sortComparer: (a, b) => a.model_name.localeCompare(b.model_name),
|
sortComparer: (a, b) => a.model_name.localeCompare(b.model_name),
|
||||||
});
|
});
|
||||||
@ -160,6 +186,29 @@ export const modelsApi = api.injectEndpoints({
|
|||||||
},
|
},
|
||||||
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
|
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
|
||||||
}),
|
}),
|
||||||
|
importMainModels: build.mutation<
|
||||||
|
ImportMainModelResponse,
|
||||||
|
ImportMainModelArg
|
||||||
|
>({
|
||||||
|
query: ({ body }) => {
|
||||||
|
return {
|
||||||
|
url: `models/import`,
|
||||||
|
method: 'POST',
|
||||||
|
body: body,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
|
||||||
|
}),
|
||||||
|
addMainModels: build.mutation<AddMainModelResponse, AddMainModelArg>({
|
||||||
|
query: ({ body }) => {
|
||||||
|
return {
|
||||||
|
url: `models/add`,
|
||||||
|
method: 'POST',
|
||||||
|
body: body,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
|
||||||
|
}),
|
||||||
deleteMainModels: build.mutation<
|
deleteMainModels: build.mutation<
|
||||||
DeleteMainModelResponse,
|
DeleteMainModelResponse,
|
||||||
DeleteMainModelArg
|
DeleteMainModelArg
|
||||||
@ -176,10 +225,11 @@ export const modelsApi = api.injectEndpoints({
|
|||||||
ConvertMainModelResponse,
|
ConvertMainModelResponse,
|
||||||
ConvertMainModelArg
|
ConvertMainModelArg
|
||||||
>({
|
>({
|
||||||
query: ({ base_model, model_name }) => {
|
query: ({ base_model, model_name, params }) => {
|
||||||
return {
|
return {
|
||||||
url: `models/convert/${base_model}/main/${model_name}`,
|
url: `models/convert/${base_model}/main/${model_name}`,
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
params: params,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
|
invalidatesTags: [{ type: 'MainModel', id: LIST_TAG }],
|
||||||
@ -328,6 +378,21 @@ export const modelsApi = api.injectEndpoints({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
getModelsInFolder: build.query<SearchFolderResponse, SearchFolderArg>({
|
||||||
|
query: (arg) => {
|
||||||
|
const folderQueryStr = queryString.stringify(arg, {});
|
||||||
|
return {
|
||||||
|
url: `/models/search?${folderQueryStr}`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
getCheckpointConfigs: build.query<CheckpointConfigsResponse, void>({
|
||||||
|
query: () => {
|
||||||
|
return {
|
||||||
|
url: `/models/ckpt_confs`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -339,6 +404,10 @@ export const {
|
|||||||
useGetVaeModelsQuery,
|
useGetVaeModelsQuery,
|
||||||
useUpdateMainModelsMutation,
|
useUpdateMainModelsMutation,
|
||||||
useDeleteMainModelsMutation,
|
useDeleteMainModelsMutation,
|
||||||
|
useImportMainModelsMutation,
|
||||||
|
useAddMainModelsMutation,
|
||||||
useConvertMainModelsMutation,
|
useConvertMainModelsMutation,
|
||||||
useMergeMainModelsMutation,
|
useMergeMainModelsMutation,
|
||||||
|
useGetModelsInFolderQuery,
|
||||||
|
useGetCheckpointConfigsQuery,
|
||||||
} = modelsApi;
|
} = modelsApi;
|
||||||
|
107
invokeai/frontend/web/src/services/api/schema.d.ts
vendored
107
invokeai/frontend/web/src/services/api/schema.d.ts
vendored
@ -84,7 +84,7 @@ export type paths = {
|
|||||||
delete: operations["del_model"];
|
delete: operations["del_model"];
|
||||||
/**
|
/**
|
||||||
* Update Model
|
* Update Model
|
||||||
* @description Add Model
|
* @description Update model contents with a new config. If the model name or base fields are changed, then the model is renamed.
|
||||||
*/
|
*/
|
||||||
patch: operations["update_model"];
|
patch: operations["update_model"];
|
||||||
};
|
};
|
||||||
@ -102,13 +102,6 @@ export type paths = {
|
|||||||
*/
|
*/
|
||||||
post: operations["add_model"];
|
post: operations["add_model"];
|
||||||
};
|
};
|
||||||
"/api/v1/models/rename/{base_model}/{model_type}/{model_name}": {
|
|
||||||
/**
|
|
||||||
* Rename Model
|
|
||||||
* @description Rename a model
|
|
||||||
*/
|
|
||||||
post: operations["rename_model"];
|
|
||||||
};
|
|
||||||
"/api/v1/models/convert/{base_model}/{model_type}/{model_name}": {
|
"/api/v1/models/convert/{base_model}/{model_type}/{model_name}": {
|
||||||
/**
|
/**
|
||||||
* Convert Model
|
* Convert Model
|
||||||
@ -1226,7 +1219,7 @@ export type components = {
|
|||||||
* @description The nodes in this graph
|
* @description The nodes in this graph
|
||||||
*/
|
*/
|
||||||
nodes?: {
|
nodes?: {
|
||||||
[key: string]: (components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["RealESRGANInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"]) | undefined;
|
[key: string]: (components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["RealESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"]) | undefined;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Edges
|
* Edges
|
||||||
@ -1269,7 +1262,7 @@ export type components = {
|
|||||||
* @description The results of node executions
|
* @description The results of node executions
|
||||||
*/
|
*/
|
||||||
results: {
|
results: {
|
||||||
[key: string]: (components["schemas"]["ImageOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["PromptOutput"] | components["schemas"]["PromptCollectionOutput"] | components["schemas"]["CompelOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["IntOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["IntCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]) | undefined;
|
[key: string]: (components["schemas"]["ImageOutput"] | components["schemas"]["MaskOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["VaeLoaderOutput"] | components["schemas"]["MetadataAccumulatorOutput"] | components["schemas"]["IntCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["CompelOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["IntOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["PromptOutput"] | components["schemas"]["PromptCollectionOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["CollectInvocationOutput"]) | undefined;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Errors
|
* Errors
|
||||||
@ -4031,40 +4024,6 @@ export type components = {
|
|||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
ResourceOrigin: "internal" | "external";
|
ResourceOrigin: "internal" | "external";
|
||||||
/**
|
|
||||||
* RestoreFaceInvocation
|
|
||||||
* @description Restores faces in an image.
|
|
||||||
*/
|
|
||||||
RestoreFaceInvocation: {
|
|
||||||
/**
|
|
||||||
* Id
|
|
||||||
* @description The id of this node. Must be unique among all nodes.
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
/**
|
|
||||||
* Is Intermediate
|
|
||||||
* @description Whether or not this node is an intermediate node.
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
is_intermediate?: boolean;
|
|
||||||
/**
|
|
||||||
* Type
|
|
||||||
* @default restore_face
|
|
||||||
* @enum {string}
|
|
||||||
*/
|
|
||||||
type?: "restore_face";
|
|
||||||
/**
|
|
||||||
* Image
|
|
||||||
* @description The input image
|
|
||||||
*/
|
|
||||||
image?: components["schemas"]["ImageField"];
|
|
||||||
/**
|
|
||||||
* Strength
|
|
||||||
* @description The strength of the restoration
|
|
||||||
* @default 0.75
|
|
||||||
*/
|
|
||||||
strength?: number;
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* ScaleLatentsInvocation
|
* ScaleLatentsInvocation
|
||||||
* @description Scales latents by a given factor.
|
* @description Scales latents by a given factor.
|
||||||
@ -4653,18 +4612,18 @@ export type components = {
|
|||||||
*/
|
*/
|
||||||
image?: components["schemas"]["ImageField"];
|
image?: components["schemas"]["ImageField"];
|
||||||
};
|
};
|
||||||
/**
|
|
||||||
* StableDiffusion2ModelFormat
|
|
||||||
* @description An enumeration.
|
|
||||||
* @enum {string}
|
|
||||||
*/
|
|
||||||
StableDiffusion2ModelFormat: "checkpoint" | "diffusers";
|
|
||||||
/**
|
/**
|
||||||
* StableDiffusion1ModelFormat
|
* StableDiffusion1ModelFormat
|
||||||
* @description An enumeration.
|
* @description An enumeration.
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
StableDiffusion1ModelFormat: "checkpoint" | "diffusers";
|
StableDiffusion1ModelFormat: "checkpoint" | "diffusers";
|
||||||
|
/**
|
||||||
|
* StableDiffusion2ModelFormat
|
||||||
|
* @description An enumeration.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
StableDiffusion2ModelFormat: "checkpoint" | "diffusers";
|
||||||
};
|
};
|
||||||
responses: never;
|
responses: never;
|
||||||
parameters: never;
|
parameters: never;
|
||||||
@ -4775,7 +4734,7 @@ export type operations = {
|
|||||||
};
|
};
|
||||||
requestBody: {
|
requestBody: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["RealESRGANInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
|
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["RealESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
responses: {
|
responses: {
|
||||||
@ -4812,7 +4771,7 @@ export type operations = {
|
|||||||
};
|
};
|
||||||
requestBody: {
|
requestBody: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["RealESRGANInvocation"] | components["schemas"]["RestoreFaceInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
|
"application/json": components["schemas"]["LoadImageInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageProcessorInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["MetadataAccumulatorInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["TextToLatentsInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["InpaintInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ParamIntInvocation"] | components["schemas"]["ParamFloatInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["RealESRGANInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["LatentsToLatentsInvocation"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
responses: {
|
responses: {
|
||||||
@ -5061,7 +5020,7 @@ export type operations = {
|
|||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Update Model
|
* Update Model
|
||||||
* @description Add Model
|
* @description Update model contents with a new config. If the model name or base fields are changed, then the model is renamed.
|
||||||
*/
|
*/
|
||||||
update_model: {
|
update_model: {
|
||||||
parameters: {
|
parameters: {
|
||||||
@ -5090,6 +5049,8 @@ export type operations = {
|
|||||||
400: never;
|
400: never;
|
||||||
/** @description The model could not be found */
|
/** @description The model could not be found */
|
||||||
404: never;
|
404: never;
|
||||||
|
/** @description There is already a model corresponding to the new name */
|
||||||
|
409: never;
|
||||||
/** @description Validation Error */
|
/** @description Validation Error */
|
||||||
422: {
|
422: {
|
||||||
content: {
|
content: {
|
||||||
@ -5160,46 +5121,6 @@ export type operations = {
|
|||||||
424: never;
|
424: never;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
|
||||||
* Rename Model
|
|
||||||
* @description Rename a model
|
|
||||||
*/
|
|
||||||
rename_model: {
|
|
||||||
parameters: {
|
|
||||||
query?: {
|
|
||||||
/** @description new model name */
|
|
||||||
new_name?: string;
|
|
||||||
/** @description new model base */
|
|
||||||
new_base?: components["schemas"]["BaseModelType"];
|
|
||||||
};
|
|
||||||
path: {
|
|
||||||
/** @description Base model */
|
|
||||||
base_model: components["schemas"]["BaseModelType"];
|
|
||||||
/** @description The type of model */
|
|
||||||
model_type: components["schemas"]["ModelType"];
|
|
||||||
/** @description current model name */
|
|
||||||
model_name: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
responses: {
|
|
||||||
/** @description The model was renamed successfully */
|
|
||||||
201: {
|
|
||||||
content: {
|
|
||||||
"application/json": components["schemas"]["StableDiffusion1ModelCheckpointConfig"] | components["schemas"]["StableDiffusion1ModelDiffusersConfig"] | components["schemas"]["VaeModelConfig"] | components["schemas"]["LoRAModelConfig"] | components["schemas"]["ControlNetModelConfig"] | components["schemas"]["TextualInversionModelConfig"] | components["schemas"]["StableDiffusion2ModelCheckpointConfig"] | components["schemas"]["StableDiffusion2ModelDiffusersConfig"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/** @description The model could not be found */
|
|
||||||
404: never;
|
|
||||||
/** @description There is already a model corresponding to the new name */
|
|
||||||
409: never;
|
|
||||||
/** @description Validation Error */
|
|
||||||
422: {
|
|
||||||
content: {
|
|
||||||
"application/json": components["schemas"]["HTTPValidationError"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* Convert Model
|
* Convert Model
|
||||||
* @description Convert a checkpoint model into a diffusers model, optionally saving to the indicated destination directory, or `models` if none.
|
* @description Convert a checkpoint model into a diffusers model, optionally saving to the indicated destination directory, or `models` if none.
|
||||||
|
@ -57,7 +57,10 @@ export type AnyModelConfig =
|
|||||||
| ControlNetModelConfig
|
| ControlNetModelConfig
|
||||||
| TextualInversionModelConfig
|
| TextualInversionModelConfig
|
||||||
| MainModelConfig;
|
| MainModelConfig;
|
||||||
|
|
||||||
export type MergeModelConfig = components['schemas']['Body_merge_models'];
|
export type MergeModelConfig = components['schemas']['Body_merge_models'];
|
||||||
|
export type ConvertModelConfig = components['schemas']['Body_convert_model'];
|
||||||
|
export type ImportModelConfig = components['schemas']['Body_import_model'];
|
||||||
|
|
||||||
// Graphs
|
// Graphs
|
||||||
export type Graph = components['schemas']['Graph'];
|
export type Graph = components['schemas']['Graph'];
|
||||||
|
Loading…
Reference in New Issue
Block a user