mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
Merge branch 'main' into pr/2058
This commit is contained in:
@@ -9,10 +9,10 @@ import { FaLanguage } from 'react-icons/fa';
|
||||
|
||||
export default function LanguagePicker() {
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
const LANGUAGES = {
|
||||
en: t('common:langEnglish'),
|
||||
ar: t('common:langArabic'),
|
||||
nl: t('common:langDutch'),
|
||||
en: t('common:langEnglish'),
|
||||
fr: t('common:langFrench'),
|
||||
de: t('common:langGerman'),
|
||||
it: t('common:langItalian'),
|
||||
@@ -35,7 +35,6 @@ export default function LanguagePicker() {
|
||||
onClick={() => i18n.changeLanguage(lang)}
|
||||
className="modal-close-btn lang-select-btn"
|
||||
aria-label={LANGUAGES[lang as keyof typeof LANGUAGES]}
|
||||
tooltip={LANGUAGES[lang as keyof typeof LANGUAGES]}
|
||||
size="sm"
|
||||
minWidth="200px"
|
||||
>
|
||||
|
||||
@@ -27,6 +27,7 @@ import type { InvokeModelConfigProps } from 'app/invokeai';
|
||||
import type { RootState } from 'app/store';
|
||||
import type { FieldInputProps, FormikProps } from 'formik';
|
||||
import { isEqual, pickBy } from 'lodash';
|
||||
import ModelConvert from './ModelConvert';
|
||||
|
||||
const selector = createSelector(
|
||||
[systemSelector],
|
||||
@@ -101,10 +102,11 @@ export default function CheckpointModelEdit() {
|
||||
|
||||
return openModel ? (
|
||||
<Flex flexDirection="column" rowGap="1rem" width="100%">
|
||||
<Flex alignItems="center">
|
||||
<Flex alignItems="center" gap={4} justifyContent="space-between">
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
{openModel}
|
||||
</Text>
|
||||
<ModelConvert model={openModel} />
|
||||
</Flex>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
import {
|
||||
Flex,
|
||||
ListItem,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Text,
|
||||
UnorderedList,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import { convertToDiffusers } from 'app/socketio/actions';
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import IAIInput from 'common/components/IAIInput';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface ModelConvertProps {
|
||||
model: string;
|
||||
}
|
||||
|
||||
export default function ModelConvert(props: ModelConvertProps) {
|
||||
const { model } = props;
|
||||
|
||||
const model_list = useAppSelector(
|
||||
(state: RootState) => state.system.model_list
|
||||
);
|
||||
|
||||
const retrievedModel = model_list[model];
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const isProcessing = useAppSelector(
|
||||
(state: RootState) => state.system.isProcessing
|
||||
);
|
||||
|
||||
const isConnected = useAppSelector(
|
||||
(state: RootState) => state.system.isConnected
|
||||
);
|
||||
|
||||
const [saveLocation, setSaveLocation] = useState<string>('same');
|
||||
const [customSaveLocation, setCustomSaveLocation] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
setSaveLocation('same');
|
||||
}, [model]);
|
||||
|
||||
const modelConvertCancelHandler = () => {
|
||||
setSaveLocation('same');
|
||||
};
|
||||
|
||||
const modelConvertHandler = () => {
|
||||
const modelToConvert = {
|
||||
model_name: model,
|
||||
save_location: saveLocation,
|
||||
custom_location:
|
||||
saveLocation === 'custom' && customSaveLocation !== ''
|
||||
? customSaveLocation
|
||||
: null,
|
||||
};
|
||||
dispatch(convertToDiffusers(modelToConvert));
|
||||
};
|
||||
|
||||
return (
|
||||
<IAIAlertDialog
|
||||
title={`${t('modelmanager:convert')} ${model}`}
|
||||
acceptCallback={modelConvertHandler}
|
||||
cancelCallback={modelConvertCancelHandler}
|
||||
acceptButtonText={`${t('modelmanager:convert')}`}
|
||||
triggerComponent={
|
||||
<IAIButton
|
||||
size={'sm'}
|
||||
aria-label={t('modelmanager:convertToDiffusers')}
|
||||
isDisabled={
|
||||
retrievedModel.status === 'active' || isProcessing || !isConnected
|
||||
}
|
||||
className=" modal-close-btn"
|
||||
marginRight="2rem"
|
||||
>
|
||||
🧨 {t('modelmanager:convertToDiffusers')}
|
||||
</IAIButton>
|
||||
}
|
||||
motionPreset="slideInBottom"
|
||||
>
|
||||
<Flex flexDirection="column" rowGap={4}>
|
||||
<Text>{t('modelmanager:convertToDiffusersHelpText1')}</Text>
|
||||
<UnorderedList>
|
||||
<ListItem>{t('modelmanager:convertToDiffusersHelpText2')}</ListItem>
|
||||
<ListItem>{t('modelmanager:convertToDiffusersHelpText3')}</ListItem>
|
||||
<ListItem>{t('modelmanager:convertToDiffusersHelpText4')}</ListItem>
|
||||
<ListItem>{t('modelmanager:convertToDiffusersHelpText5')}</ListItem>
|
||||
</UnorderedList>
|
||||
<Text>{t('modelmanager:convertToDiffusersHelpText6')}</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex flexDir="column" gap={4}>
|
||||
<Flex marginTop="1rem" flexDir="column" gap={2}>
|
||||
<Text fontWeight="bold">
|
||||
{t('modelmanager:convertToDiffusersSaveLocation')}
|
||||
</Text>
|
||||
<RadioGroup value={saveLocation} onChange={(v) => setSaveLocation(v)}>
|
||||
<Flex gap={4}>
|
||||
<Radio value="same">
|
||||
<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">
|
||||
{t('modelmanager:invokeRoot')}
|
||||
</Tooltip>
|
||||
</Radio>
|
||||
|
||||
<Radio value="custom">
|
||||
<Tooltip label="Save converted model in a custom folder">
|
||||
{t('modelmanager:custom')}
|
||||
</Tooltip>
|
||||
</Radio>
|
||||
</Flex>
|
||||
</RadioGroup>
|
||||
</Flex>
|
||||
|
||||
{saveLocation === 'custom' && (
|
||||
<Flex flexDirection="column" rowGap={2}>
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
fontSize="sm"
|
||||
color="var(--text-color-secondary)"
|
||||
>
|
||||
{t('modelmanager:customSaveLocation')}
|
||||
</Text>
|
||||
<IAIInput
|
||||
value={customSaveLocation}
|
||||
onChange={(e) => {
|
||||
if (e.target.value !== '')
|
||||
setCustomSaveLocation(e.target.value);
|
||||
}}
|
||||
width="25rem"
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</IAIAlertDialog>
|
||||
);
|
||||
}
|
||||
@@ -83,6 +83,7 @@ export default function ModelListItem(props: ModelListItemProps) {
|
||||
>
|
||||
{t('modelmanager:load')}
|
||||
</Button>
|
||||
|
||||
<IAIIconButton
|
||||
icon={<EditIcon />}
|
||||
size="sm"
|
||||
|
||||
@@ -3,7 +3,16 @@ import IAICheckbox from 'common/components/IAICheckbox';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import React from 'react';
|
||||
|
||||
import { Box, Flex, FormControl, HStack, Text, VStack } from '@chakra-ui/react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
FormControl,
|
||||
HStack,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Text,
|
||||
VStack,
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
@@ -135,6 +144,8 @@ export default function SearchModels() {
|
||||
);
|
||||
|
||||
const [modelsToAdd, setModelsToAdd] = React.useState<string[]>([]);
|
||||
const [modelType, setModelType] = React.useState<string>('v1');
|
||||
const [pathToConfig, setPathToConfig] = React.useState<string>('');
|
||||
|
||||
const resetSearchModelHandler = () => {
|
||||
dispatch(setSearchFolder(null));
|
||||
@@ -167,11 +178,19 @@ export default function SearchModels() {
|
||||
const modelsToBeAdded = foundModels?.filter((foundModel) =>
|
||||
modelsToAdd.includes(foundModel.name)
|
||||
);
|
||||
|
||||
const configFiles = {
|
||||
v1: 'configs/stable-diffusion/v1-inference.yaml',
|
||||
v2: 'configs/stable-diffusion/v2-inference-v.yaml',
|
||||
inpainting: 'configs/stable-diffusion/v1-inpainting-inference.yaml',
|
||||
custom: pathToConfig,
|
||||
};
|
||||
|
||||
modelsToBeAdded?.forEach((model) => {
|
||||
const modelFormat = {
|
||||
name: model.name,
|
||||
description: '',
|
||||
config: 'configs/stable-diffusion/v1-inference.yaml',
|
||||
config: configFiles[modelType as keyof typeof configFiles],
|
||||
weights: model.location,
|
||||
vae: '',
|
||||
width: 512,
|
||||
@@ -346,6 +365,55 @@ export default function SearchModels() {
|
||||
{t('modelmanager:addSelected')}
|
||||
</IAIButton>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
gap={4}
|
||||
backgroundColor="var(--background-color)"
|
||||
padding="1rem 1rem"
|
||||
borderRadius="0.2rem"
|
||||
flexDirection="column"
|
||||
>
|
||||
<Flex gap={4}>
|
||||
<Text fontWeight="bold" color="var(--text-color-secondary)">
|
||||
Pick Model Type:
|
||||
</Text>
|
||||
<RadioGroup
|
||||
value={modelType}
|
||||
onChange={(v) => setModelType(v)}
|
||||
defaultValue="v1"
|
||||
name="model_type"
|
||||
>
|
||||
<Flex gap={4}>
|
||||
<Radio value="v1">{t('modelmanager:v1')}</Radio>
|
||||
<Radio value="v2">{t('modelmanager:v2')}</Radio>
|
||||
<Radio value="inpainting">
|
||||
{t('modelmanager:inpainting')}
|
||||
</Radio>
|
||||
<Radio value="custom">{t('modelmanager:customConfig')}</Radio>
|
||||
</Flex>
|
||||
</RadioGroup>
|
||||
</Flex>
|
||||
|
||||
{modelType === 'custom' && (
|
||||
<Flex flexDirection="column" rowGap={2}>
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
fontSize="sm"
|
||||
color="var(--text-color-secondary)"
|
||||
>
|
||||
{t('modelmanager:pathToCustomConfig')}
|
||||
</Text>
|
||||
<IAIInput
|
||||
value={pathToConfig}
|
||||
onChange={(e) => {
|
||||
if (e.target.value !== '') setPathToConfig(e.target.value);
|
||||
}}
|
||||
width="42.5rem"
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
rowGap="1rem"
|
||||
flexDirection="column"
|
||||
|
||||
@@ -214,6 +214,12 @@ export const systemSlice = createSlice({
|
||||
state.isProcessing = true;
|
||||
state.currentStatusHasSteps = false;
|
||||
},
|
||||
modelConvertRequested: (state) => {
|
||||
state.currentStatus = i18n.t('common:statusConvertingModel');
|
||||
state.isCancelable = false;
|
||||
state.isProcessing = true;
|
||||
state.currentStatusHasSteps = false;
|
||||
},
|
||||
setSaveIntermediatesInterval: (state, action: PayloadAction<number>) => {
|
||||
state.saveIntermediatesInterval = action.payload;
|
||||
},
|
||||
@@ -265,6 +271,7 @@ export const {
|
||||
setModelList,
|
||||
setIsCancelable,
|
||||
modelChangeRequested,
|
||||
modelConvertRequested,
|
||||
setSaveIntermediatesInterval,
|
||||
setEnableImageDebugging,
|
||||
generationRequested,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { Feature } from 'app/features';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import FaceRestoreSettings from 'features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreSettings';
|
||||
import FaceRestoreToggle from 'features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreToggle';
|
||||
import ImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageFit';
|
||||
@@ -16,10 +15,7 @@ import ParametersAccordion from 'features/parameters/components/ParametersAccord
|
||||
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
|
||||
import NegativePromptInput from 'features/parameters/components/PromptInput/NegativePromptInput';
|
||||
import PromptInput from 'features/parameters/components/PromptInput/PromptInput';
|
||||
import { setHiresFix } from 'features/parameters/store/postprocessingSlice';
|
||||
import InvokeOptionsPanel from 'features/ui/components/InvokeParametersPanel';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function ImageToImagePanel() {
|
||||
@@ -56,17 +52,6 @@ export default function ImageToImagePanel() {
|
||||
},
|
||||
};
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeTabName === 'img2img') {
|
||||
const handleChangeHiresFix = () => dispatch(setHiresFix(false));
|
||||
handleChangeHiresFix();
|
||||
}
|
||||
}, [activeTabName, dispatch]);
|
||||
|
||||
return (
|
||||
<InvokeOptionsPanel>
|
||||
<Flex flexDir="column" rowGap="0.5rem">
|
||||
|
||||
Reference in New Issue
Block a user