mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-01-21 04:28:24 -05:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac22652686 | ||
|
|
77cfec5cc8 | ||
|
|
3e4420c1ae | ||
|
|
f8181ab1b3 | ||
|
|
3dfeead9b8 | ||
|
|
3da0be7eb9 | ||
|
|
31e5f4bb0e | ||
|
|
2164674b01 | ||
|
|
8f2a646286 | ||
|
|
5ff4dd26bb | ||
|
|
e342ca872f | ||
|
|
062a369044 | ||
|
|
e4a2f56ad1 | ||
|
|
1df30f7260 | ||
|
|
14c4650801 | ||
|
|
f155b03eee | ||
|
|
ddaf753f7b | ||
|
|
e6d14c708c | ||
|
|
7f81a95b20 | ||
|
|
6a49eec606 | ||
|
|
fd67b18c9a | ||
|
|
9affdbbaad | ||
|
|
8d300bddd0 | ||
|
|
aa2c94be9e | ||
|
|
4c79350300 | ||
|
|
10e1d623c3 | ||
|
|
aa1f827271 | ||
|
|
fb113b9077 | ||
|
|
6edeb4e072 | ||
|
|
006075483d | ||
|
|
52bd29d484 | ||
|
|
3bb81bedbd | ||
|
|
b8b46aec09 | ||
|
|
4d2b87ea01 | ||
|
|
611f31c057 | ||
|
|
b60adc31d0 | ||
|
|
a98ed3a5ba | ||
|
|
f057d5c85b |
BIN
docs/assets/troubleshooting/broken-dependency.png
Normal file
BIN
docs/assets/troubleshooting/broken-dependency.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 131 KiB |
@@ -80,11 +80,11 @@ Q&A</a>]
|
||||
|
||||
!!! note
|
||||
|
||||
This fork is rapidly evolving. Please use the [Issues tab](https://github.com/invoke-ai/InvokeAI/issues) to report bugs and make feature requests. Be sure to use the provided templates. They will help aid diagnose issues faster.
|
||||
This software is rapidly evolving. Please use the [Issues tab](https://github.com/invoke-ai/InvokeAI/issues) to report bugs and make feature requests. Be sure to use the provided templates. They will help aid diagnose issues faster.
|
||||
|
||||
## :octicons-package-dependencies-24: Installation
|
||||
|
||||
This fork is supported across Linux, Windows and Macintosh. Linux users can use
|
||||
This software is supported across Linux, Windows and Macintosh. Linux users can use
|
||||
either an Nvidia-based card (with CUDA support) or an AMD card (using the ROCm
|
||||
driver).
|
||||
|
||||
@@ -95,6 +95,8 @@ driver).
|
||||
This method is recommended for experienced users and developers
|
||||
#### [Docker Installation](installation/040_INSTALL_DOCKER.md)
|
||||
This method is recommended for those familiar with running Docker containers
|
||||
#### [Installation Troubleshooting](installation/010_INSTALL_AUTOMATED.md#troubleshooting)
|
||||
Installation troubleshooting guide.
|
||||
### Other Installation Guides
|
||||
- [PyPatchMatch](installation/060_INSTALL_PATCHMATCH.md)
|
||||
- [XFormers](installation/070_INSTALL_XFORMERS.md)
|
||||
@@ -230,7 +232,7 @@ encouraged to do so.
|
||||
|
||||
## :octicons-person-24: Contributors
|
||||
|
||||
This fork is a combined effort of various people from across the world.
|
||||
This software is a combined effort of various people from across the world.
|
||||
[Check out the list of all these amazing people](other/CONTRIBUTORS.md). We
|
||||
thank them for their time, hard work and effort.
|
||||
|
||||
|
||||
@@ -372,8 +372,71 @@ experimental versions later.
|
||||
Once InvokeAI is installed, do not move or remove this directory."
|
||||
|
||||
|
||||
<a name="troubleshooting"></a>
|
||||
## Troubleshooting
|
||||
|
||||
### _OSErrors on Windows while installing dependencies_
|
||||
|
||||
During a zip file installation or an online update, installation stops
|
||||
with an error like this:
|
||||
|
||||
{:width="800px"}
|
||||
|
||||
This seems to happen particularly often with the `pydantic` and
|
||||
`numpy` packages. The most reliable solution requires several manual
|
||||
steps to complete installation.
|
||||
|
||||
Open up a Powershell window and navigate to the `invokeai` directory
|
||||
created by the installer. Then give the following series of commands:
|
||||
|
||||
```cmd
|
||||
rm .\.venv -r -force
|
||||
python -mvenv .venv
|
||||
.\.venv\Scripts\activate
|
||||
pip install invokeai
|
||||
invokeai-configure --root .
|
||||
```
|
||||
|
||||
If you see anything marked as an error during this process please stop
|
||||
and seek help on the Discord [installation support
|
||||
channel](https://discord.com/channels/1020123559063990373/1041391462190956654). A
|
||||
few warning messages are OK.
|
||||
|
||||
If you are updating from a previous version, this should restore your
|
||||
system to a working state. If you are installing from scratch, there
|
||||
is one additional command to give:
|
||||
|
||||
```cmd
|
||||
wget -O invoke.bat https://raw.githubusercontent.com/invoke-ai/InvokeAI/main/installer/templates/invoke.bat.in
|
||||
```
|
||||
|
||||
This will create the `invoke.bat` script needed to launch InvokeAI and
|
||||
its related programs.
|
||||
|
||||
|
||||
### _Stable Diffusion XL Generation Fails after Trying to Load unet_
|
||||
|
||||
InvokeAI is working in other respects, but when trying to generate
|
||||
images with Stable Diffusion XL you get a "Server Error". The text log
|
||||
in the launch window contains this log line above several more lines of
|
||||
error messages:
|
||||
|
||||
```INFO --> Loading model:D:\LONG\PATH\TO\MODEL, type sdxl:main:unet```
|
||||
|
||||
This failure mode occurs when there is a network glitch during
|
||||
downloading the very large SDXL model.
|
||||
|
||||
To address this, first go to the Web Model Manager and delete the
|
||||
Stable-Diffusion-XL-base-1.X model. Then navigate to HuggingFace and
|
||||
manually download the .safetensors version of the model. The 1.0
|
||||
version is located at
|
||||
https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/tree/main
|
||||
and the file is named `sd_xl_base_1.0.safetensors`.
|
||||
|
||||
Save this file to disk and then reenter the Model Manager. Navigate to
|
||||
Import Models->Add Model, then type (or drag-and-drop) the path to the
|
||||
.safetensors file. Press "Add Model".
|
||||
|
||||
### _Package dependency conflicts_
|
||||
|
||||
If you have previously installed InvokeAI or another Stable Diffusion
|
||||
|
||||
@@ -211,7 +211,7 @@ def invoke_api():
|
||||
port = find_port(app_config.port)
|
||||
if port != app_config.port:
|
||||
logger.warn(f"Port {app_config.port} in use, using port {port}")
|
||||
|
||||
|
||||
# Start our own event loop for eventing usage
|
||||
loop = asyncio.new_event_loop()
|
||||
config = uvicorn.Config(
|
||||
@@ -229,7 +229,7 @@ def invoke_api():
|
||||
l.handlers.clear()
|
||||
for ch in logger.handlers:
|
||||
l.addHandler(ch)
|
||||
|
||||
|
||||
loop.run_until_complete(server.serve())
|
||||
|
||||
|
||||
|
||||
@@ -292,15 +292,16 @@ class SDXLTextToLatentsInvocation(BaseInvocation):
|
||||
)
|
||||
|
||||
num_inference_steps = self.steps
|
||||
scheduler.set_timesteps(num_inference_steps)
|
||||
timesteps = scheduler.timesteps
|
||||
|
||||
latents = latents * scheduler.init_noise_sigma
|
||||
|
||||
unet_info = context.services.model_manager.get_model(**self.unet.unet.dict(), context=context)
|
||||
do_classifier_free_guidance = True
|
||||
cross_attention_kwargs = None
|
||||
with unet_info as unet:
|
||||
scheduler.set_timesteps(num_inference_steps, device=unet.device)
|
||||
timesteps = scheduler.timesteps
|
||||
|
||||
latents = latents.to(device=unet.device, dtype=unet.dtype) * scheduler.init_noise_sigma
|
||||
|
||||
extra_step_kwargs = dict()
|
||||
if "eta" in set(inspect.signature(scheduler.step).parameters.keys()):
|
||||
extra_step_kwargs.update(
|
||||
@@ -537,27 +538,28 @@ class SDXLLatentsToLatentsInvocation(BaseInvocation):
|
||||
scheduler_name=self.scheduler,
|
||||
)
|
||||
|
||||
# apply denoising_start
|
||||
num_inference_steps = self.steps
|
||||
scheduler.set_timesteps(num_inference_steps)
|
||||
|
||||
t_start = int(round(self.denoising_start * num_inference_steps))
|
||||
timesteps = scheduler.timesteps[t_start * scheduler.order :]
|
||||
num_inference_steps = num_inference_steps - t_start
|
||||
|
||||
# apply noise(if provided)
|
||||
if self.noise is not None and timesteps.shape[0] > 0:
|
||||
noise = context.services.latents.get(self.noise.latents_name)
|
||||
latents = scheduler.add_noise(latents, noise, timesteps[:1])
|
||||
del noise
|
||||
|
||||
unet_info = context.services.model_manager.get_model(
|
||||
**self.unet.unet.dict(),
|
||||
context=context,
|
||||
)
|
||||
|
||||
do_classifier_free_guidance = True
|
||||
cross_attention_kwargs = None
|
||||
with unet_info as unet:
|
||||
# apply denoising_start
|
||||
num_inference_steps = self.steps
|
||||
scheduler.set_timesteps(num_inference_steps, device=unet.device)
|
||||
|
||||
t_start = int(round(self.denoising_start * num_inference_steps))
|
||||
timesteps = scheduler.timesteps[t_start * scheduler.order :]
|
||||
num_inference_steps = num_inference_steps - t_start
|
||||
|
||||
# apply noise(if provided)
|
||||
if self.noise is not None and timesteps.shape[0] > 0:
|
||||
noise = context.services.latents.get(self.noise.latents_name)
|
||||
latents = scheduler.add_noise(latents, noise, timesteps[:1])
|
||||
del noise
|
||||
|
||||
# apply scheduler extra args
|
||||
extra_step_kwargs = dict()
|
||||
if "eta" in set(inspect.signature(scheduler.step).parameters.keys()):
|
||||
|
||||
@@ -57,7 +57,7 @@ class LoRAModel(ModelBase):
|
||||
|
||||
@classproperty
|
||||
def save_to_config(cls) -> bool:
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def detect_format(cls, path: str):
|
||||
|
||||
169
invokeai/frontend/web/dist/assets/App-58b095d3.js
vendored
169
invokeai/frontend/web/dist/assets/App-58b095d3.js
vendored
File diff suppressed because one or more lines are too long
169
invokeai/frontend/web/dist/assets/App-d6f88f50.js
vendored
Normal file
169
invokeai/frontend/web/dist/assets/App-d6f88f50.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
invokeai/frontend/web/dist/assets/MantineProvider-c592f969.js
vendored
Normal file
1
invokeai/frontend/web/dist/assets/MantineProvider-c592f969.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
310
invokeai/frontend/web/dist/assets/ThemeLocaleProvider-94e0a1e5.js
vendored
Normal file
310
invokeai/frontend/web/dist/assets/ThemeLocaleProvider-94e0a1e5.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
invokeai/frontend/web/dist/index.html
vendored
2
invokeai/frontend/web/dist/index.html
vendored
@@ -12,7 +12,7 @@
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="./assets/index-5a784cdd.js"></script>
|
||||
<script type="module" crossorigin src="./assets/index-bad7ff83.js"></script>
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
|
||||
1
invokeai/frontend/web/dist/locales/en.json
vendored
1
invokeai/frontend/web/dist/locales/en.json
vendored
@@ -340,6 +340,7 @@
|
||||
"allModels": "All Models",
|
||||
"checkpointModels": "Checkpoints",
|
||||
"diffusersModels": "Diffusers",
|
||||
"loraModels": "LoRAs",
|
||||
"safetensorModels": "SafeTensors",
|
||||
"modelAdded": "Model Added",
|
||||
"modelUpdated": "Model Updated",
|
||||
|
||||
@@ -340,6 +340,7 @@
|
||||
"allModels": "All Models",
|
||||
"checkpointModels": "Checkpoints",
|
||||
"diffusersModels": "Diffusers",
|
||||
"loraModels": "LoRAs",
|
||||
"safetensorModels": "SafeTensors",
|
||||
"modelAdded": "Model Added",
|
||||
"modelUpdated": "Model Updated",
|
||||
|
||||
@@ -148,7 +148,7 @@ const ParamPositiveConditioning = () => {
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: shouldPinParametersPanel ? 6 : 0,
|
||||
top: shouldPinParametersPanel ? 5 : 0,
|
||||
insetInlineEnd: 0,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import ParamNegativeConditioning from 'features/parameters/components/Parameters/Core/ParamNegativeConditioning';
|
||||
import ParamPositiveConditioning from 'features/parameters/components/Parameters/Core/ParamPositiveConditioning';
|
||||
|
||||
export default function ParamPromptArea() {
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: 'column',
|
||||
gap: 2,
|
||||
}}
|
||||
>
|
||||
<ParamPositiveConditioning />
|
||||
<ParamNegativeConditioning />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { components } from 'services/api/schema';
|
||||
|
||||
export const MODEL_TYPE_MAP = {
|
||||
'sd-1': 'Stable Diffusion 1.x',
|
||||
'sd-2': 'Stable Diffusion 2.x',
|
||||
@@ -5,6 +7,13 @@ export const MODEL_TYPE_MAP = {
|
||||
'sdxl-refiner': 'Stable Diffusion XL Refiner',
|
||||
};
|
||||
|
||||
export const MODEL_TYPE_SHORT_MAP = {
|
||||
'sd-1': 'SD1',
|
||||
'sd-2': 'SD2',
|
||||
sdxl: 'SDXL',
|
||||
'sdxl-refiner': 'SDXLR',
|
||||
};
|
||||
|
||||
export const clipSkipMap = {
|
||||
'sd-1': {
|
||||
maxClip: 12,
|
||||
@@ -23,3 +32,12 @@ export const clipSkipMap = {
|
||||
markers: [0, 1, 2, 3, 5, 10, 15, 20, 24],
|
||||
},
|
||||
};
|
||||
|
||||
type LoRAModelFormatMap = {
|
||||
[key in components['schemas']['LoRAModelFormat']]: string;
|
||||
};
|
||||
|
||||
export const LORA_MODEL_FORMAT_MAP: LoRAModelFormatMap = {
|
||||
lycoris: 'LyCORIS',
|
||||
diffusers: 'Diffusers',
|
||||
};
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import { FaLink } from 'react-icons/fa';
|
||||
import { setShouldConcatSDXLStylePrompt } from '../store/sdxlSlice';
|
||||
|
||||
export default function ParamSDXLConcatButton() {
|
||||
const shouldConcatSDXLStylePrompt = useAppSelector(
|
||||
(state: RootState) => state.sdxl.shouldConcatSDXLStylePrompt
|
||||
);
|
||||
|
||||
const shouldPinParametersPanel = useAppSelector(
|
||||
(state: RootState) => state.ui.shouldPinParametersPanel
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleShouldConcatPromptChange = () => {
|
||||
dispatch(setShouldConcatSDXLStylePrompt(!shouldConcatSDXLStylePrompt));
|
||||
};
|
||||
|
||||
return (
|
||||
<IAIIconButton
|
||||
aria-label="Concat"
|
||||
tooltip="Concatenates Basic Prompt with Style (Recommended)"
|
||||
variant="outline"
|
||||
isChecked={shouldConcatSDXLStylePrompt}
|
||||
onClick={handleShouldConcatPromptChange}
|
||||
icon={<FaLink />}
|
||||
size="xs"
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
insetInlineEnd: 1,
|
||||
top: shouldPinParametersPanel ? 12 : 20,
|
||||
border: 'none',
|
||||
color: shouldConcatSDXLStylePrompt ? 'accent.500' : 'base.500',
|
||||
_hover: {
|
||||
bg: 'none',
|
||||
},
|
||||
}}
|
||||
></IAIIconButton>
|
||||
);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAISwitch from 'common/components/IAISwitch';
|
||||
import { ChangeEvent } from 'react';
|
||||
import { setShouldConcatSDXLStylePrompt } from '../store/sdxlSlice';
|
||||
|
||||
export default function ParamSDXLConcatPrompt() {
|
||||
const shouldConcatSDXLStylePrompt = useAppSelector(
|
||||
(state: RootState) => state.sdxl.shouldConcatSDXLStylePrompt
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleShouldConcatPromptChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(setShouldConcatSDXLStylePrompt(e.target.checked));
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
px: 2,
|
||||
}}
|
||||
>
|
||||
<IAISwitch
|
||||
label="Concat Style Prompt"
|
||||
tooltip="Concatenates Basic Prompt with Style (Recommended)"
|
||||
isChecked={shouldConcatSDXLStylePrompt}
|
||||
onChange={handleShouldConcatPromptChange}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -13,15 +13,20 @@ import { useIsReadyToInvoke } from 'common/hooks/useIsReadyToInvoke';
|
||||
import AddEmbeddingButton from 'features/embedding/components/AddEmbeddingButton';
|
||||
import ParamEmbeddingPopover from 'features/embedding/components/ParamEmbeddingPopover';
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { setNegativeStylePromptSDXL } from '../store/sdxlSlice';
|
||||
import SDXLConcatLink from './SDXLConcatLink';
|
||||
|
||||
const promptInputSelector = createSelector(
|
||||
[stateSelector, activeTabNameSelector],
|
||||
({ sdxl }, activeTabName) => {
|
||||
const { negativeStylePrompt, shouldConcatSDXLStylePrompt } = sdxl;
|
||||
|
||||
return {
|
||||
prompt: sdxl.negativeStylePrompt,
|
||||
prompt: negativeStylePrompt,
|
||||
shouldConcatSDXLStylePrompt,
|
||||
activeTabName,
|
||||
};
|
||||
},
|
||||
@@ -37,11 +42,13 @@ const promptInputSelector = createSelector(
|
||||
*/
|
||||
const ParamSDXLNegativeStyleConditioning = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { prompt, activeTabName } = useAppSelector(promptInputSelector);
|
||||
const isReady = useIsReadyToInvoke();
|
||||
const promptRef = useRef<HTMLTextAreaElement>(null);
|
||||
const { isOpen, onClose, onOpen } = useDisclosure();
|
||||
|
||||
const { prompt, activeTabName, shouldConcatSDXLStylePrompt } =
|
||||
useAppSelector(promptInputSelector);
|
||||
|
||||
const handleChangePrompt = useCallback(
|
||||
(e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
dispatch(setNegativeStylePromptSDXL(e.target.value));
|
||||
@@ -111,6 +118,20 @@ const ParamSDXLNegativeStyleConditioning = () => {
|
||||
|
||||
return (
|
||||
<Box position="relative">
|
||||
<AnimatePresence>
|
||||
{shouldConcatSDXLStylePrompt && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
left: '3',
|
||||
w: '94%',
|
||||
top: '-17px',
|
||||
}}
|
||||
>
|
||||
<SDXLConcatLink />
|
||||
</Box>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
<FormControl>
|
||||
<ParamEmbeddingPopover
|
||||
isOpen={isOpen}
|
||||
|
||||
@@ -13,15 +13,20 @@ import { useIsReadyToInvoke } from 'common/hooks/useIsReadyToInvoke';
|
||||
import AddEmbeddingButton from 'features/embedding/components/AddEmbeddingButton';
|
||||
import ParamEmbeddingPopover from 'features/embedding/components/ParamEmbeddingPopover';
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { setPositiveStylePromptSDXL } from '../store/sdxlSlice';
|
||||
import SDXLConcatLink from './SDXLConcatLink';
|
||||
|
||||
const promptInputSelector = createSelector(
|
||||
[stateSelector, activeTabNameSelector],
|
||||
({ sdxl }, activeTabName) => {
|
||||
const { positiveStylePrompt, shouldConcatSDXLStylePrompt } = sdxl;
|
||||
|
||||
return {
|
||||
prompt: sdxl.positiveStylePrompt,
|
||||
prompt: positiveStylePrompt,
|
||||
shouldConcatSDXLStylePrompt,
|
||||
activeTabName,
|
||||
};
|
||||
},
|
||||
@@ -37,11 +42,13 @@ const promptInputSelector = createSelector(
|
||||
*/
|
||||
const ParamSDXLPositiveStyleConditioning = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { prompt, activeTabName } = useAppSelector(promptInputSelector);
|
||||
const isReady = useIsReadyToInvoke();
|
||||
const promptRef = useRef<HTMLTextAreaElement>(null);
|
||||
const { isOpen, onClose, onOpen } = useDisclosure();
|
||||
|
||||
const { prompt, activeTabName, shouldConcatSDXLStylePrompt } =
|
||||
useAppSelector(promptInputSelector);
|
||||
|
||||
const handleChangePrompt = useCallback(
|
||||
(e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
dispatch(setPositiveStylePromptSDXL(e.target.value));
|
||||
@@ -111,6 +118,20 @@ const ParamSDXLPositiveStyleConditioning = () => {
|
||||
|
||||
return (
|
||||
<Box position="relative">
|
||||
<AnimatePresence>
|
||||
{shouldConcatSDXLStylePrompt && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
left: '3',
|
||||
w: '94%',
|
||||
top: '-17px',
|
||||
}}
|
||||
>
|
||||
<SDXLConcatLink />
|
||||
</Box>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
<FormControl>
|
||||
<ParamEmbeddingPopover
|
||||
isOpen={isOpen}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import ParamNegativeConditioning from 'features/parameters/components/Parameters/Core/ParamNegativeConditioning';
|
||||
import ParamPositiveConditioning from 'features/parameters/components/Parameters/Core/ParamPositiveConditioning';
|
||||
import ParamSDXLConcatButton from './ParamSDXLConcatButton';
|
||||
import ParamSDXLNegativeStyleConditioning from './ParamSDXLNegativeStyleConditioning';
|
||||
import ParamSDXLPositiveStyleConditioning from './ParamSDXLPositiveStyleConditioning';
|
||||
|
||||
export default function ParamSDXLPromptArea() {
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: 'column',
|
||||
gap: 2,
|
||||
}}
|
||||
>
|
||||
<ParamPositiveConditioning />
|
||||
<ParamSDXLConcatButton />
|
||||
<ParamSDXLPositiveStyleConditioning />
|
||||
<ParamNegativeConditioning />
|
||||
<ParamSDXLNegativeStyleConditioning />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { CSSObject } from '@emotion/react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { FaLink } from 'react-icons/fa';
|
||||
|
||||
const sharedConcatLinkStyle: CSSObject = {
|
||||
position: 'absolute',
|
||||
bg: 'none',
|
||||
w: 'full',
|
||||
minH: 2,
|
||||
borderRadius: 0,
|
||||
borderLeft: 'none',
|
||||
borderRight: 'none',
|
||||
zIndex: 2,
|
||||
maskImage:
|
||||
'radial-gradient(circle at center, black, black 65%, black 30%, black 15%, transparent)',
|
||||
};
|
||||
|
||||
export default function SDXLConcatLink() {
|
||||
return (
|
||||
<Flex>
|
||||
<Box
|
||||
as={motion.div}
|
||||
initial={{
|
||||
scaleX: 0,
|
||||
borderWidth: 0,
|
||||
display: 'none',
|
||||
}}
|
||||
animate={{
|
||||
display: ['block', 'block', 'block', 'none'],
|
||||
scaleX: [0, 0.25, 0.5, 1],
|
||||
borderWidth: [0, 3, 3, 0],
|
||||
transition: { duration: 0.37, times: [0, 0.25, 0.5, 1] },
|
||||
}}
|
||||
sx={{
|
||||
top: '1px',
|
||||
borderTop: 'none',
|
||||
borderColor: 'base.400',
|
||||
...sharedConcatLinkStyle,
|
||||
_dark: {
|
||||
borderColor: 'accent.500',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
as={motion.div}
|
||||
initial={{
|
||||
opacity: 0,
|
||||
scale: 0,
|
||||
}}
|
||||
animate={{
|
||||
opacity: [0, 1, 1, 1],
|
||||
scale: [0, 0.75, 1.5, 1],
|
||||
transition: { duration: 0.42, times: [0, 0.25, 0.5, 1] },
|
||||
}}
|
||||
exit={{
|
||||
opacity: 0,
|
||||
scale: 0,
|
||||
}}
|
||||
sx={{
|
||||
zIndex: 3,
|
||||
position: 'absolute',
|
||||
left: '48%',
|
||||
top: '3px',
|
||||
p: 1,
|
||||
borderRadius: 4,
|
||||
bg: 'accent.400',
|
||||
color: 'base.50',
|
||||
_dark: {
|
||||
bg: 'accent.500',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<FaLink size={12} />
|
||||
</Box>
|
||||
<Box
|
||||
as={motion.div}
|
||||
initial={{
|
||||
scaleX: 0,
|
||||
borderWidth: 0,
|
||||
display: 'none',
|
||||
}}
|
||||
animate={{
|
||||
display: ['block', 'block', 'block', 'none'],
|
||||
scaleX: [0, 0.25, 0.5, 1],
|
||||
borderWidth: [0, 3, 3, 0],
|
||||
transition: { duration: 0.37, times: [0, 0.25, 0.5, 1] },
|
||||
}}
|
||||
sx={{
|
||||
top: '17px',
|
||||
borderBottom: 'none',
|
||||
borderColor: 'base.400',
|
||||
...sharedConcatLinkStyle,
|
||||
_dark: {
|
||||
borderColor: 'accent.500',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -1,34 +1,14 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/ParamDynamicPromptsCollapse';
|
||||
import ParamNegativeConditioning from 'features/parameters/components/Parameters/Core/ParamNegativeConditioning';
|
||||
import ParamPositiveConditioning from 'features/parameters/components/Parameters/Core/ParamPositiveConditioning';
|
||||
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
|
||||
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
|
||||
import ParamSDXLConcatPrompt from './ParamSDXLConcatPrompt';
|
||||
import ParamSDXLNegativeStyleConditioning from './ParamSDXLNegativeStyleConditioning';
|
||||
import ParamSDXLPositiveStyleConditioning from './ParamSDXLPositiveStyleConditioning';
|
||||
import ParamSDXLPromptArea from './ParamSDXLPromptArea';
|
||||
import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse';
|
||||
import SDXLImageToImageTabCoreParameters from './SDXLImageToImageTabCoreParameters';
|
||||
|
||||
const SDXLImageToImageTabParameters = () => {
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: 'column',
|
||||
gap: 2,
|
||||
p: 2,
|
||||
borderRadius: 4,
|
||||
bg: 'base.100',
|
||||
_dark: { bg: 'base.850' },
|
||||
}}
|
||||
>
|
||||
<ParamPositiveConditioning />
|
||||
<ParamSDXLPositiveStyleConditioning />
|
||||
<ParamNegativeConditioning />
|
||||
<ParamSDXLNegativeStyleConditioning />
|
||||
<ParamSDXLConcatPrompt />
|
||||
</Flex>
|
||||
<ParamSDXLPromptArea />
|
||||
<ProcessButtons />
|
||||
<SDXLImageToImageTabCoreParameters />
|
||||
<ParamSDXLRefinerCollapse />
|
||||
|
||||
@@ -1,34 +1,14 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/ParamDynamicPromptsCollapse';
|
||||
import ParamNegativeConditioning from 'features/parameters/components/Parameters/Core/ParamNegativeConditioning';
|
||||
import ParamPositiveConditioning from 'features/parameters/components/Parameters/Core/ParamPositiveConditioning';
|
||||
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
|
||||
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
|
||||
import TextToImageTabCoreParameters from 'features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters';
|
||||
import ParamSDXLConcatPrompt from './ParamSDXLConcatPrompt';
|
||||
import ParamSDXLNegativeStyleConditioning from './ParamSDXLNegativeStyleConditioning';
|
||||
import ParamSDXLPositiveStyleConditioning from './ParamSDXLPositiveStyleConditioning';
|
||||
import ParamSDXLPromptArea from './ParamSDXLPromptArea';
|
||||
import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse';
|
||||
|
||||
const SDXLTextToImageTabParameters = () => {
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: 'column',
|
||||
gap: 2,
|
||||
p: 2,
|
||||
borderRadius: 4,
|
||||
bg: 'base.100',
|
||||
_dark: { bg: 'base.850' },
|
||||
}}
|
||||
>
|
||||
<ParamPositiveConditioning />
|
||||
<ParamSDXLPositiveStyleConditioning />
|
||||
<ParamNegativeConditioning />
|
||||
<ParamSDXLNegativeStyleConditioning />
|
||||
<ParamSDXLConcatPrompt />
|
||||
</Flex>
|
||||
<ParamSDXLPromptArea />
|
||||
<ProcessButtons />
|
||||
<TextToImageTabCoreParameters />
|
||||
<ParamSDXLRefinerCollapse />
|
||||
|
||||
@@ -2,20 +2,18 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para
|
||||
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
|
||||
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
|
||||
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
|
||||
import ParamNegativeConditioning from 'features/parameters/components/Parameters/Core/ParamNegativeConditioning';
|
||||
import ParamPositiveConditioning from 'features/parameters/components/Parameters/Core/ParamPositiveConditioning';
|
||||
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
|
||||
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
|
||||
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
|
||||
// import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse';
|
||||
import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea';
|
||||
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
|
||||
import ImageToImageTabCoreParameters from './ImageToImageTabCoreParameters';
|
||||
|
||||
const ImageToImageTabParameters = () => {
|
||||
return (
|
||||
<>
|
||||
<ParamPositiveConditioning />
|
||||
<ParamNegativeConditioning />
|
||||
<ParamPromptArea />
|
||||
<ProcessButtons />
|
||||
<ImageToImageTabCoreParameters />
|
||||
<ParamControlNetCollapse />
|
||||
|
||||
@@ -3,20 +3,31 @@ import { Flex, Text } from '@chakra-ui/react';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
MainModelConfigEntity,
|
||||
DiffusersModelConfigEntity,
|
||||
LoRAModelConfigEntity,
|
||||
useGetMainModelsQuery,
|
||||
useGetLoRAModelsQuery,
|
||||
} from 'services/api/endpoints/models';
|
||||
import CheckpointModelEdit from './ModelManagerPanel/CheckpointModelEdit';
|
||||
import DiffusersModelEdit from './ModelManagerPanel/DiffusersModelEdit';
|
||||
import LoRAModelEdit from './ModelManagerPanel/LoRAModelEdit';
|
||||
import ModelList from './ModelManagerPanel/ModelList';
|
||||
import { ALL_BASE_MODELS } from 'services/api/constants';
|
||||
|
||||
export default function ModelManagerPanel() {
|
||||
const [selectedModelId, setSelectedModelId] = useState<string>();
|
||||
const { model } = useGetMainModelsQuery(ALL_BASE_MODELS, {
|
||||
const { mainModel } = useGetMainModelsQuery(ALL_BASE_MODELS, {
|
||||
selectFromResult: ({ data }) => ({
|
||||
model: selectedModelId ? data?.entities[selectedModelId] : undefined,
|
||||
mainModel: selectedModelId ? data?.entities[selectedModelId] : undefined,
|
||||
}),
|
||||
});
|
||||
const { loraModel } = useGetLoRAModelsQuery(undefined, {
|
||||
selectFromResult: ({ data }) => ({
|
||||
loraModel: selectedModelId ? data?.entities[selectedModelId] : undefined,
|
||||
}),
|
||||
});
|
||||
|
||||
const model = mainModel ? mainModel : loraModel;
|
||||
|
||||
return (
|
||||
<Flex sx={{ gap: 8, w: 'full', h: 'full' }}>
|
||||
@@ -30,7 +41,7 @@ export default function ModelManagerPanel() {
|
||||
}
|
||||
|
||||
type ModelEditProps = {
|
||||
model: MainModelConfigEntity | undefined;
|
||||
model: MainModelConfigEntity | LoRAModelConfigEntity | undefined;
|
||||
};
|
||||
|
||||
const ModelEdit = (props: ModelEditProps) => {
|
||||
@@ -41,7 +52,16 @@ const ModelEdit = (props: ModelEditProps) => {
|
||||
}
|
||||
|
||||
if (model?.model_format === 'diffusers') {
|
||||
return <DiffusersModelEdit key={model.id} model={model} />;
|
||||
return (
|
||||
<DiffusersModelEdit
|
||||
key={model.id}
|
||||
model={model as DiffusersModelConfigEntity}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (model?.model_type === 'lora') {
|
||||
return <LoRAModelEdit key={model.id} model={model} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
import { Divider, Flex, Text } from '@chakra-ui/react';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { makeToast } from 'features/system/util/makeToast';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||
import { selectIsBusy } from 'features/system/store/systemSelectors';
|
||||
import { addToast } from 'features/system/store/systemSlice';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
LORA_MODEL_FORMAT_MAP,
|
||||
MODEL_TYPE_MAP,
|
||||
} from 'features/parameters/types/constants';
|
||||
import {
|
||||
LoRAModelConfigEntity,
|
||||
useUpdateLoRAModelsMutation,
|
||||
} from 'services/api/endpoints/models';
|
||||
import { LoRAModelConfig } from 'services/api/types';
|
||||
import BaseModelSelect from '../shared/BaseModelSelect';
|
||||
|
||||
type LoRAModelEditProps = {
|
||||
model: LoRAModelConfigEntity;
|
||||
};
|
||||
|
||||
export default function LoRAModelEdit(props: LoRAModelEditProps) {
|
||||
const isBusy = useAppSelector(selectIsBusy);
|
||||
|
||||
const { model } = props;
|
||||
|
||||
const [updateLoRAModel, { isLoading }] = useUpdateLoRAModelsMutation();
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const loraEditForm = useForm<LoRAModelConfig>({
|
||||
initialValues: {
|
||||
model_name: model.model_name ? model.model_name : '',
|
||||
base_model: model.base_model,
|
||||
model_type: 'lora',
|
||||
path: model.path ? model.path : '',
|
||||
description: model.description ? model.description : '',
|
||||
model_format: model.model_format,
|
||||
},
|
||||
validate: {
|
||||
path: (value) =>
|
||||
value.trim().length === 0 ? 'Must provide a path' : null,
|
||||
},
|
||||
});
|
||||
|
||||
const editModelFormSubmitHandler = useCallback(
|
||||
(values: LoRAModelConfig) => {
|
||||
const responseBody = {
|
||||
base_model: model.base_model,
|
||||
model_name: model.model_name,
|
||||
body: values,
|
||||
};
|
||||
|
||||
updateLoRAModel(responseBody)
|
||||
.unwrap()
|
||||
.then((payload) => {
|
||||
loraEditForm.setValues(payload as LoRAModelConfig);
|
||||
dispatch(
|
||||
addToast(
|
||||
makeToast({
|
||||
title: t('modelManager.modelUpdated'),
|
||||
status: 'success',
|
||||
})
|
||||
)
|
||||
);
|
||||
})
|
||||
.catch((_) => {
|
||||
loraEditForm.reset();
|
||||
dispatch(
|
||||
addToast(
|
||||
makeToast({
|
||||
title: t('modelManager.modelUpdateFailed'),
|
||||
status: 'error',
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
},
|
||||
[
|
||||
dispatch,
|
||||
loraEditForm,
|
||||
model.base_model,
|
||||
model.model_name,
|
||||
t,
|
||||
updateLoRAModel,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex flexDirection="column" rowGap={4} width="100%">
|
||||
<Flex flexDirection="column">
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
{model.model_name}
|
||||
</Text>
|
||||
<Text fontSize="sm" color="base.400">
|
||||
{MODEL_TYPE_MAP[model.base_model]} Model ⋅{' '}
|
||||
{LORA_MODEL_FORMAT_MAP[model.model_format]} format
|
||||
</Text>
|
||||
</Flex>
|
||||
<Divider />
|
||||
|
||||
<form
|
||||
onSubmit={loraEditForm.onSubmit((values) =>
|
||||
editModelFormSubmitHandler(values)
|
||||
)}
|
||||
>
|
||||
<Flex flexDirection="column" overflowY="scroll" gap={4}>
|
||||
<IAIMantineTextInput
|
||||
label={t('modelManager.name')}
|
||||
{...loraEditForm.getInputProps('model_name')}
|
||||
/>
|
||||
<IAIMantineTextInput
|
||||
label={t('modelManager.description')}
|
||||
{...loraEditForm.getInputProps('description')}
|
||||
/>
|
||||
<BaseModelSelect {...loraEditForm.getInputProps('base_model')} />
|
||||
<IAIMantineTextInput
|
||||
label={t('modelManager.modelLocation')}
|
||||
{...loraEditForm.getInputProps('path')}
|
||||
/>
|
||||
<IAIButton
|
||||
type="submit"
|
||||
isDisabled={isBusy || isLoading}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
{t('modelManager.updateModel')}
|
||||
</IAIButton>
|
||||
</Flex>
|
||||
</form>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
MainModelConfigEntity,
|
||||
useGetMainModelsQuery,
|
||||
useGetLoRAModelsQuery,
|
||||
LoRAModelConfigEntity,
|
||||
} from 'services/api/endpoints/models';
|
||||
import ModelListItem from './ModelListItem';
|
||||
import { ALL_BASE_MODELS } from 'services/api/constants';
|
||||
@@ -20,22 +22,42 @@ type ModelListProps = {
|
||||
|
||||
type ModelFormat = 'images' | 'checkpoint' | 'diffusers';
|
||||
|
||||
type ModelType = 'main' | 'lora';
|
||||
|
||||
type CombinedModelFormat = ModelFormat | 'lora';
|
||||
|
||||
const ModelList = (props: ModelListProps) => {
|
||||
const { selectedModelId, setSelectedModelId } = props;
|
||||
const { t } = useTranslation();
|
||||
const [nameFilter, setNameFilter] = useState<string>('');
|
||||
const [modelFormatFilter, setModelFormatFilter] =
|
||||
useState<ModelFormat>('images');
|
||||
useState<CombinedModelFormat>('images');
|
||||
|
||||
const { filteredDiffusersModels } = useGetMainModelsQuery(ALL_BASE_MODELS, {
|
||||
selectFromResult: ({ data }) => ({
|
||||
filteredDiffusersModels: modelsFilter(data, 'diffusers', nameFilter),
|
||||
filteredDiffusersModels: modelsFilter(
|
||||
data,
|
||||
'main',
|
||||
'diffusers',
|
||||
nameFilter
|
||||
),
|
||||
}),
|
||||
});
|
||||
|
||||
const { filteredCheckpointModels } = useGetMainModelsQuery(ALL_BASE_MODELS, {
|
||||
selectFromResult: ({ data }) => ({
|
||||
filteredCheckpointModels: modelsFilter(data, 'checkpoint', nameFilter),
|
||||
filteredCheckpointModels: modelsFilter(
|
||||
data,
|
||||
'main',
|
||||
'checkpoint',
|
||||
nameFilter
|
||||
),
|
||||
}),
|
||||
});
|
||||
|
||||
const { filteredLoraModels } = useGetLoRAModelsQuery(undefined, {
|
||||
selectFromResult: ({ data }) => ({
|
||||
filteredLoraModels: modelsFilter(data, 'lora', undefined, nameFilter),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -68,6 +90,13 @@ const ModelList = (props: ModelListProps) => {
|
||||
>
|
||||
{t('modelManager.checkpointModels')}
|
||||
</IAIButton>
|
||||
<IAIButton
|
||||
size="sm"
|
||||
onClick={() => setModelFormatFilter('lora')}
|
||||
isChecked={modelFormatFilter === 'lora'}
|
||||
>
|
||||
{t('modelManager.loraModels')}
|
||||
</IAIButton>
|
||||
</ButtonGroup>
|
||||
|
||||
<IAIInput
|
||||
@@ -118,6 +147,24 @@ const ModelList = (props: ModelListProps) => {
|
||||
</Flex>
|
||||
</StyledModelContainer>
|
||||
)}
|
||||
{['images', 'lora'].includes(modelFormatFilter) &&
|
||||
filteredLoraModels.length > 0 && (
|
||||
<StyledModelContainer>
|
||||
<Flex sx={{ gap: 2, flexDir: 'column' }}>
|
||||
<Text variant="subtext" fontSize="sm">
|
||||
LoRAs
|
||||
</Text>
|
||||
{filteredLoraModels.map((model) => (
|
||||
<ModelListItem
|
||||
key={model.id}
|
||||
model={model}
|
||||
isSelected={selectedModelId === model.id}
|
||||
setSelectedModelId={setSelectedModelId}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
</StyledModelContainer>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
@@ -126,12 +173,13 @@ const ModelList = (props: ModelListProps) => {
|
||||
|
||||
export default ModelList;
|
||||
|
||||
const modelsFilter = (
|
||||
data: EntityState<MainModelConfigEntity> | undefined,
|
||||
model_format: ModelFormat,
|
||||
const modelsFilter = <T extends MainModelConfigEntity | LoRAModelConfigEntity>(
|
||||
data: EntityState<T> | undefined,
|
||||
model_type: ModelType,
|
||||
model_format: ModelFormat | undefined,
|
||||
nameFilter: string
|
||||
) => {
|
||||
const filteredModels: MainModelConfigEntity[] = [];
|
||||
const filteredModels: T[] = [];
|
||||
forEach(data?.entities, (model) => {
|
||||
if (!model) {
|
||||
return;
|
||||
@@ -141,9 +189,11 @@ const modelsFilter = (
|
||||
.toLowerCase()
|
||||
.includes(nameFilter.toLowerCase());
|
||||
|
||||
const matchesFormat = model.model_format === model_format;
|
||||
const matchesFormat =
|
||||
model_format === undefined || model.model_format === model_format;
|
||||
const matchesType = model.model_type === model_type;
|
||||
|
||||
if (matchesFilter && matchesFormat) {
|
||||
if (matchesFilter && matchesFormat && matchesType) {
|
||||
filteredModels.push(model);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,29 +9,26 @@ import { selectIsBusy } from 'features/system/store/systemSelectors';
|
||||
import { addToast } from 'features/system/store/systemSlice';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MODEL_TYPE_SHORT_MAP } from 'features/parameters/types/constants';
|
||||
import {
|
||||
MainModelConfigEntity,
|
||||
LoRAModelConfigEntity,
|
||||
useDeleteMainModelsMutation,
|
||||
useDeleteLoRAModelsMutation,
|
||||
} from 'services/api/endpoints/models';
|
||||
|
||||
type ModelListItemProps = {
|
||||
model: MainModelConfigEntity;
|
||||
model: MainModelConfigEntity | LoRAModelConfigEntity;
|
||||
isSelected: boolean;
|
||||
setSelectedModelId: (v: string | undefined) => void;
|
||||
};
|
||||
|
||||
const modelBaseTypeMap = {
|
||||
'sd-1': 'SD1',
|
||||
'sd-2': 'SD2',
|
||||
sdxl: 'SDXL',
|
||||
'sdxl-refiner': 'SDXLR',
|
||||
};
|
||||
|
||||
export default function ModelListItem(props: ModelListItemProps) {
|
||||
const isBusy = useAppSelector(selectIsBusy);
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const [deleteMainModel] = useDeleteMainModelsMutation();
|
||||
const [deleteLoRAModel] = useDeleteLoRAModelsMutation();
|
||||
|
||||
const { model, isSelected, setSelectedModelId } = props;
|
||||
|
||||
@@ -40,7 +37,10 @@ export default function ModelListItem(props: ModelListItemProps) {
|
||||
}, [model.id, setSelectedModelId]);
|
||||
|
||||
const handleModelDelete = useCallback(() => {
|
||||
deleteMainModel(model)
|
||||
const method = { main: deleteMainModel, lora: deleteLoRAModel }[
|
||||
model.model_type
|
||||
];
|
||||
method(model)
|
||||
.unwrap()
|
||||
.then((_) => {
|
||||
dispatch(
|
||||
@@ -60,14 +60,21 @@ export default function ModelListItem(props: ModelListItemProps) {
|
||||
title: `${t('modelManager.modelDeleteFailed')}: ${
|
||||
model.model_name
|
||||
}`,
|
||||
status: 'success',
|
||||
status: 'error',
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
setSelectedModelId(undefined);
|
||||
}, [deleteMainModel, model, setSelectedModelId, dispatch, t]);
|
||||
}, [
|
||||
deleteMainModel,
|
||||
deleteLoRAModel,
|
||||
model,
|
||||
setSelectedModelId,
|
||||
dispatch,
|
||||
t,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Flex sx={{ gap: 2, alignItems: 'center', w: 'full' }}>
|
||||
@@ -100,8 +107,8 @@ export default function ModelListItem(props: ModelListItemProps) {
|
||||
<Flex gap={4} alignItems="center">
|
||||
<Badge minWidth={14} p={0.5} fontSize="sm" variant="solid">
|
||||
{
|
||||
modelBaseTypeMap[
|
||||
model.base_model as keyof typeof modelBaseTypeMap
|
||||
MODEL_TYPE_SHORT_MAP[
|
||||
model.base_model as keyof typeof MODEL_TYPE_SHORT_MAP
|
||||
]
|
||||
}
|
||||
</Badge>
|
||||
|
||||
@@ -2,20 +2,18 @@ import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/Para
|
||||
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
|
||||
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
|
||||
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
|
||||
import ParamNegativeConditioning from 'features/parameters/components/Parameters/Core/ParamNegativeConditioning';
|
||||
import ParamPositiveConditioning from 'features/parameters/components/Parameters/Core/ParamPositiveConditioning';
|
||||
import ParamNoiseCollapse from 'features/parameters/components/Parameters/Noise/ParamNoiseCollapse';
|
||||
import ParamSeamlessCollapse from 'features/parameters/components/Parameters/Seamless/ParamSeamlessCollapse';
|
||||
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
|
||||
// import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse';
|
||||
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
|
||||
import ParamPromptArea from '../../../../parameters/components/Parameters/Prompt/ParamPromptArea';
|
||||
import TextToImageTabCoreParameters from './TextToImageTabCoreParameters';
|
||||
|
||||
const TextToImageTabParameters = () => {
|
||||
return (
|
||||
<>
|
||||
<ParamPositiveConditioning />
|
||||
<ParamNegativeConditioning />
|
||||
<ParamPromptArea />
|
||||
<ProcessButtons />
|
||||
<TextToImageTabCoreParameters />
|
||||
<ParamControlNetCollapse />
|
||||
|
||||
@@ -4,18 +4,16 @@ import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Adv
|
||||
import ParamInfillAndScalingCollapse from 'features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillAndScalingCollapse';
|
||||
import ParamSeamCorrectionCollapse from 'features/parameters/components/Parameters/Canvas/SeamCorrection/ParamSeamCorrectionCollapse';
|
||||
import ParamControlNetCollapse from 'features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse';
|
||||
import ParamNegativeConditioning from 'features/parameters/components/Parameters/Core/ParamNegativeConditioning';
|
||||
import ParamPositiveConditioning from 'features/parameters/components/Parameters/Core/ParamPositiveConditioning';
|
||||
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
|
||||
// import ParamVariationCollapse from 'features/parameters/components/Parameters/Variations/ParamVariationCollapse';
|
||||
import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea';
|
||||
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
|
||||
import UnifiedCanvasCoreParameters from './UnifiedCanvasCoreParameters';
|
||||
|
||||
const UnifiedCanvasParameters = () => {
|
||||
return (
|
||||
<>
|
||||
<ParamPositiveConditioning />
|
||||
<ParamNegativeConditioning />
|
||||
<ParamPromptArea />
|
||||
<ProcessButtons />
|
||||
<UnifiedCanvasCoreParameters />
|
||||
<ParamControlNetCollapse />
|
||||
|
||||
@@ -52,9 +52,17 @@ type UpdateMainModelArg = {
|
||||
body: MainModelConfig;
|
||||
};
|
||||
|
||||
type UpdateLoRAModelArg = {
|
||||
base_model: BaseModelType;
|
||||
model_name: string;
|
||||
body: LoRAModelConfig;
|
||||
};
|
||||
|
||||
type UpdateMainModelResponse =
|
||||
paths['/api/v1/models/{base_model}/{model_type}/{model_name}']['patch']['responses']['200']['content']['application/json'];
|
||||
|
||||
type UpdateLoRAModelResponse = UpdateMainModelResponse;
|
||||
|
||||
type DeleteMainModelArg = {
|
||||
base_model: BaseModelType;
|
||||
model_name: string;
|
||||
@@ -62,6 +70,10 @@ type DeleteMainModelArg = {
|
||||
|
||||
type DeleteMainModelResponse = void;
|
||||
|
||||
type DeleteLoRAModelArg = DeleteMainModelArg;
|
||||
|
||||
type DeleteLoRAModelResponse = void;
|
||||
|
||||
type ConvertMainModelArg = {
|
||||
base_model: BaseModelType;
|
||||
model_name: string;
|
||||
@@ -320,6 +332,31 @@ export const modelsApi = api.injectEndpoints({
|
||||
);
|
||||
},
|
||||
}),
|
||||
updateLoRAModels: build.mutation<
|
||||
UpdateLoRAModelResponse,
|
||||
UpdateLoRAModelArg
|
||||
>({
|
||||
query: ({ base_model, model_name, body }) => {
|
||||
return {
|
||||
url: `models/${base_model}/lora/${model_name}`,
|
||||
method: 'PATCH',
|
||||
body: body,
|
||||
};
|
||||
},
|
||||
invalidatesTags: [{ type: 'LoRAModel', id: LIST_TAG }],
|
||||
}),
|
||||
deleteLoRAModels: build.mutation<
|
||||
DeleteLoRAModelResponse,
|
||||
DeleteLoRAModelArg
|
||||
>({
|
||||
query: ({ base_model, model_name }) => {
|
||||
return {
|
||||
url: `models/${base_model}/lora/${model_name}`,
|
||||
method: 'DELETE',
|
||||
};
|
||||
},
|
||||
invalidatesTags: [{ type: 'LoRAModel', id: LIST_TAG }],
|
||||
}),
|
||||
getControlNetModels: build.query<
|
||||
EntityState<ControlNetModelConfigEntity>,
|
||||
void
|
||||
@@ -467,6 +504,8 @@ export const {
|
||||
useAddMainModelsMutation,
|
||||
useConvertMainModelsMutation,
|
||||
useMergeMainModelsMutation,
|
||||
useDeleteLoRAModelsMutation,
|
||||
useUpdateLoRAModelsMutation,
|
||||
useSyncModelsMutation,
|
||||
useGetModelsInFolderQuery,
|
||||
useGetCheckpointConfigsQuery,
|
||||
|
||||
@@ -13,6 +13,15 @@ const invokeAI = defineStyle((props) => ({
|
||||
var(--invokeai-colors-base-200) 70%,
|
||||
var(--invokeai-colors-base-200) 100%)`,
|
||||
},
|
||||
_disabled: {
|
||||
'::-webkit-resizer': {
|
||||
backgroundImage: `linear-gradient(135deg,
|
||||
var(--invokeai-colors-base-50) 0%,
|
||||
var(--invokeai-colors-base-50) 70%,
|
||||
var(--invokeai-colors-base-200) 70%,
|
||||
var(--invokeai-colors-base-200) 100%)`,
|
||||
},
|
||||
},
|
||||
_dark: {
|
||||
'::-webkit-resizer': {
|
||||
backgroundImage: `linear-gradient(135deg,
|
||||
@@ -21,6 +30,15 @@ const invokeAI = defineStyle((props) => ({
|
||||
var(--invokeai-colors-base-800) 70%,
|
||||
var(--invokeai-colors-base-800) 100%)`,
|
||||
},
|
||||
_disabled: {
|
||||
'::-webkit-resizer': {
|
||||
backgroundImage: `linear-gradient(135deg,
|
||||
var(--invokeai-colors-base-900) 0%,
|
||||
var(--invokeai-colors-base-900) 70%,
|
||||
var(--invokeai-colors-base-800) 70%,
|
||||
var(--invokeai-colors-base-800) 100%)`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "3.0.1rc2"
|
||||
__version__ = "3.0.1"
|
||||
|
||||
Reference in New Issue
Block a user