mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'feat/ip-adapter' of github.com:invoke-ai/InvokeAI into feat/ip-adapter
This commit is contained in:
commit
29b4ddcc7f
@ -49,6 +49,7 @@
|
|||||||
"close": "Close",
|
"close": "Close",
|
||||||
"communityLabel": "Community",
|
"communityLabel": "Community",
|
||||||
"controlNet": "Controlnet",
|
"controlNet": "Controlnet",
|
||||||
|
"ipAdapter": "IP Adapter",
|
||||||
"darkMode": "Dark Mode",
|
"darkMode": "Dark Mode",
|
||||||
"discordLabel": "Discord",
|
"discordLabel": "Discord",
|
||||||
"dontAskMeAgain": "Don't ask me again",
|
"dontAskMeAgain": "Don't ask me again",
|
||||||
@ -191,7 +192,11 @@
|
|||||||
"showAdvanced": "Show Advanced",
|
"showAdvanced": "Show Advanced",
|
||||||
"toggleControlNet": "Toggle this ControlNet",
|
"toggleControlNet": "Toggle this ControlNet",
|
||||||
"w": "W",
|
"w": "W",
|
||||||
"weight": "Weight"
|
"weight": "Weight",
|
||||||
|
"enableIPAdapter": "Enable IP Adapter",
|
||||||
|
"ipAdapterModel": "Adapter Model",
|
||||||
|
"resetIPAdapterImage": "Reset IP Adapter Image",
|
||||||
|
"ipAdapterImageFallback": "No IP Adapter Image Selected"
|
||||||
},
|
},
|
||||||
"embedding": {
|
"embedding": {
|
||||||
"addEmbedding": "Add Embedding",
|
"addEmbedding": "Add Embedding",
|
||||||
@ -1036,6 +1041,7 @@
|
|||||||
"serverError": "Server Error",
|
"serverError": "Server Error",
|
||||||
"setCanvasInitialImage": "Set as canvas initial image",
|
"setCanvasInitialImage": "Set as canvas initial image",
|
||||||
"setControlImage": "Set as control image",
|
"setControlImage": "Set as control image",
|
||||||
|
"setIPAdapterImage": "Set as IP Adapter Image",
|
||||||
"setInitialImage": "Set as initial image",
|
"setInitialImage": "Set as initial image",
|
||||||
"setNodeField": "Set as node field",
|
"setNodeField": "Set as node field",
|
||||||
"tempFoldersEmptied": "Temp Folder Emptied",
|
"tempFoldersEmptied": "Temp Folder Emptied",
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
||||||
import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
import {
|
||||||
|
controlNetReset,
|
||||||
|
ipAdapterStateReset,
|
||||||
|
} from 'features/controlNet/store/controlNetSlice';
|
||||||
import { getImageUsage } from 'features/deleteImageModal/store/selectors';
|
import { getImageUsage } from 'features/deleteImageModal/store/selectors';
|
||||||
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
||||||
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
||||||
@ -18,6 +21,7 @@ export const addDeleteBoardAndImagesFulfilledListener = () => {
|
|||||||
let wasCanvasReset = false;
|
let wasCanvasReset = false;
|
||||||
let wasNodeEditorReset = false;
|
let wasNodeEditorReset = false;
|
||||||
let wasControlNetReset = false;
|
let wasControlNetReset = false;
|
||||||
|
let wasIPAdapterReset = false;
|
||||||
|
|
||||||
const state = getState();
|
const state = getState();
|
||||||
deleted_images.forEach((image_name) => {
|
deleted_images.forEach((image_name) => {
|
||||||
@ -42,6 +46,11 @@ export const addDeleteBoardAndImagesFulfilledListener = () => {
|
|||||||
dispatch(controlNetReset());
|
dispatch(controlNetReset());
|
||||||
wasControlNetReset = true;
|
wasControlNetReset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (imageUsage.isIPAdapterImage && !wasIPAdapterReset) {
|
||||||
|
dispatch(ipAdapterStateReset());
|
||||||
|
wasIPAdapterReset = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,7 @@ import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
|||||||
import {
|
import {
|
||||||
controlNetImageChanged,
|
controlNetImageChanged,
|
||||||
controlNetProcessedImageChanged,
|
controlNetProcessedImageChanged,
|
||||||
|
ipAdapterImageChanged,
|
||||||
} from 'features/controlNet/store/controlNetSlice';
|
} from 'features/controlNet/store/controlNetSlice';
|
||||||
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
|
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
|
||||||
import { isModalOpenChanged } from 'features/deleteImageModal/store/slice';
|
import { isModalOpenChanged } from 'features/deleteImageModal/store/slice';
|
||||||
@ -110,6 +111,14 @@ export const addRequestedSingleImageDeletionListener = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove IP Adapter Set Image if image is deleted.
|
||||||
|
if (
|
||||||
|
getState().controlNet.ipAdapterInfo.adapterImage?.image_name ===
|
||||||
|
imageDTO.image_name
|
||||||
|
) {
|
||||||
|
dispatch(ipAdapterImageChanged(null));
|
||||||
|
}
|
||||||
|
|
||||||
// reset nodes that use the deleted images
|
// reset nodes that use the deleted images
|
||||||
getState().nodes.nodes.forEach((node) => {
|
getState().nodes.nodes.forEach((node) => {
|
||||||
if (!isInvocationNode(node)) {
|
if (!isInvocationNode(node)) {
|
||||||
@ -227,6 +236,14 @@ export const addRequestedMultipleImageDeletionListener = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove IP Adapter Set Image if image is deleted.
|
||||||
|
if (
|
||||||
|
getState().controlNet.ipAdapterInfo.adapterImage?.image_name ===
|
||||||
|
imageDTO.image_name
|
||||||
|
) {
|
||||||
|
dispatch(ipAdapterImageChanged(null));
|
||||||
|
}
|
||||||
|
|
||||||
// reset nodes that use the deleted images
|
// reset nodes that use the deleted images
|
||||||
getState().nodes.nodes.forEach((node) => {
|
getState().nodes.nodes.forEach((node) => {
|
||||||
if (!isInvocationNode(node)) {
|
if (!isInvocationNode(node)) {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
|
import { parseify } from 'common/util/serialize';
|
||||||
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
||||||
import { controlNetImageChanged } from 'features/controlNet/store/controlNetSlice';
|
import {
|
||||||
|
controlNetImageChanged,
|
||||||
|
ipAdapterImageChanged,
|
||||||
|
} from 'features/controlNet/store/controlNetSlice';
|
||||||
import {
|
import {
|
||||||
TypesafeDraggableData,
|
TypesafeDraggableData,
|
||||||
TypesafeDroppableData,
|
TypesafeDroppableData,
|
||||||
@ -14,7 +18,6 @@ import {
|
|||||||
import { initialImageChanged } from 'features/parameters/store/generationSlice';
|
import { initialImageChanged } from 'features/parameters/store/generationSlice';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
import { startAppListening } from '../';
|
import { startAppListening } from '../';
|
||||||
import { parseify } from 'common/util/serialize';
|
|
||||||
|
|
||||||
export const dndDropped = createAction<{
|
export const dndDropped = createAction<{
|
||||||
overData: TypesafeDroppableData;
|
overData: TypesafeDroppableData;
|
||||||
@ -99,6 +102,18 @@ export const addImageDroppedListener = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image dropped on IP Adapter image
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
overData.actionType === 'SET_IP_ADAPTER_IMAGE' &&
|
||||||
|
activeData.payloadType === 'IMAGE_DTO' &&
|
||||||
|
activeData.payload.imageDTO
|
||||||
|
) {
|
||||||
|
dispatch(ipAdapterImageChanged(activeData.payload.imageDTO));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image dropped on Canvas
|
* Image dropped on Canvas
|
||||||
*/
|
*/
|
||||||
|
@ -19,6 +19,7 @@ export const addImageToDeleteSelectedListener = () => {
|
|||||||
imagesUsage.some((i) => i.isCanvasImage) ||
|
imagesUsage.some((i) => i.isCanvasImage) ||
|
||||||
imagesUsage.some((i) => i.isInitialImage) ||
|
imagesUsage.some((i) => i.isInitialImage) ||
|
||||||
imagesUsage.some((i) => i.isControlNetImage) ||
|
imagesUsage.some((i) => i.isControlNetImage) ||
|
||||||
|
imagesUsage.some((i) => i.isIPAdapterImage) ||
|
||||||
imagesUsage.some((i) => i.isNodesImage);
|
imagesUsage.some((i) => i.isNodesImage);
|
||||||
|
|
||||||
if (shouldConfirmOnDelete || isImageInUse) {
|
if (shouldConfirmOnDelete || isImageInUse) {
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import { UseToastOptions } from '@chakra-ui/react';
|
import { UseToastOptions } from '@chakra-ui/react';
|
||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
||||||
import { controlNetImageChanged } from 'features/controlNet/store/controlNetSlice';
|
import {
|
||||||
|
controlNetImageChanged,
|
||||||
|
ipAdapterImageChanged,
|
||||||
|
} from 'features/controlNet/store/controlNetSlice';
|
||||||
import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
|
import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
|
||||||
import { initialImageChanged } from 'features/parameters/store/generationSlice';
|
import { initialImageChanged } from 'features/parameters/store/generationSlice';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { t } from 'i18next';
|
||||||
import { omit } from 'lodash-es';
|
import { omit } from 'lodash-es';
|
||||||
import { boardsApi } from 'services/api/endpoints/boards';
|
import { boardsApi } from 'services/api/endpoints/boards';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { imagesApi } from '../../../../../services/api/endpoints/images';
|
import { imagesApi } from '../../../../../services/api/endpoints/images';
|
||||||
import { t } from 'i18next';
|
|
||||||
|
|
||||||
const DEFAULT_UPLOADED_TOAST: UseToastOptions = {
|
const DEFAULT_UPLOADED_TOAST: UseToastOptions = {
|
||||||
title: t('toast.imageUploaded'),
|
title: t('toast.imageUploaded'),
|
||||||
@ -99,6 +102,17 @@ export const addImageUploadedFulfilledListener = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (postUploadAction?.type === 'SET_IP_ADAPTER_IMAGE') {
|
||||||
|
dispatch(ipAdapterImageChanged(imageDTO));
|
||||||
|
dispatch(
|
||||||
|
addToast({
|
||||||
|
...DEFAULT_UPLOADED_TOAST,
|
||||||
|
description: t('toast.setIPAdapterImage'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (postUploadAction?.type === 'SET_INITIAL_IMAGE') {
|
if (postUploadAction?.type === 'SET_INITIAL_IMAGE') {
|
||||||
dispatch(initialImageChanged(imageDTO));
|
dispatch(initialImageChanged(imageDTO));
|
||||||
dispatch(
|
dispatch(
|
||||||
|
@ -86,7 +86,10 @@ export const store = configureStore({
|
|||||||
.concat(autoBatchEnhancer());
|
.concat(autoBatchEnhancer());
|
||||||
},
|
},
|
||||||
middleware: (getDefaultMiddleware) =>
|
middleware: (getDefaultMiddleware) =>
|
||||||
getDefaultMiddleware({ immutableCheck: false })
|
getDefaultMiddleware({
|
||||||
|
serializableCheck: false,
|
||||||
|
immutableCheck: false,
|
||||||
|
})
|
||||||
.concat(api.middleware)
|
.concat(api.middleware)
|
||||||
.concat(dynamicMiddlewares)
|
.concat(dynamicMiddlewares)
|
||||||
.prepend(listenerMiddleware.middleware),
|
.prepend(listenerMiddleware.middleware),
|
||||||
|
@ -18,6 +18,7 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useToggle } from 'react-use';
|
import { useToggle } from 'react-use';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import ControlNetImagePreview from './ControlNetImagePreview';
|
import ControlNetImagePreview from './ControlNetImagePreview';
|
||||||
@ -28,7 +29,6 @@ import ParamControlNetBeginEnd from './parameters/ParamControlNetBeginEnd';
|
|||||||
import ParamControlNetControlMode from './parameters/ParamControlNetControlMode';
|
import ParamControlNetControlMode from './parameters/ParamControlNetControlMode';
|
||||||
import ParamControlNetProcessorSelect from './parameters/ParamControlNetProcessorSelect';
|
import ParamControlNetProcessorSelect from './parameters/ParamControlNetProcessorSelect';
|
||||||
import ParamControlNetResizeMode from './parameters/ParamControlNetResizeMode';
|
import ParamControlNetResizeMode from './parameters/ParamControlNetResizeMode';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
type ControlNetProps = {
|
type ControlNetProps = {
|
||||||
controlNet: ControlNetConfig;
|
controlNet: ControlNetConfig;
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import ParamIPAdapterFeatureToggle from './ParamIPAdapterFeatureToggle';
|
||||||
|
import ParamIPAdapterImage from './ParamIPAdapterImage';
|
||||||
|
import ParamIPAdapterModelSelect from './ParamIPAdapterModelSelect';
|
||||||
|
import ParamIPAdapterWeight from './ParamIPAdapterWeight';
|
||||||
|
|
||||||
|
const IPAdapterPanel = () => {
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
flexDir: 'column',
|
||||||
|
gap: 3,
|
||||||
|
paddingInline: 3,
|
||||||
|
paddingBlock: 2,
|
||||||
|
paddingBottom: 5,
|
||||||
|
borderRadius: 'base',
|
||||||
|
position: 'relative',
|
||||||
|
bg: 'base.250',
|
||||||
|
_dark: {
|
||||||
|
bg: 'base.750',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ParamIPAdapterFeatureToggle />
|
||||||
|
<ParamIPAdapterImage />
|
||||||
|
<ParamIPAdapterModelSelect />
|
||||||
|
<ParamIPAdapterWeight />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(IPAdapterPanel);
|
@ -0,0 +1,41 @@
|
|||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
|
import { isIPAdapterEnableToggled } from 'features/controlNet/store/controlNetSlice';
|
||||||
|
import { memo, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const selector = createSelector(
|
||||||
|
stateSelector,
|
||||||
|
(state) => {
|
||||||
|
const { isIPAdapterEnabled } = state.controlNet;
|
||||||
|
|
||||||
|
return { isIPAdapterEnabled };
|
||||||
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
const ParamIPAdapterFeatureToggle = () => {
|
||||||
|
const { isIPAdapterEnabled } = useAppSelector(selector);
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleChange = useCallback(() => {
|
||||||
|
dispatch(isIPAdapterEnableToggled());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAISwitch
|
||||||
|
label={t('controlnet.enableIPAdapter')}
|
||||||
|
isChecked={isIPAdapterEnabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
formControlProps={{
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ParamIPAdapterFeatureToggle);
|
@ -0,0 +1,93 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||||
|
import { ipAdapterImageChanged } from 'features/controlNet/store/controlNetSlice';
|
||||||
|
import {
|
||||||
|
TypesafeDraggableData,
|
||||||
|
TypesafeDroppableData,
|
||||||
|
} from 'features/dnd/types';
|
||||||
|
import { memo, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaUndo } from 'react-icons/fa';
|
||||||
|
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
|
const ParamIPAdapterImage = () => {
|
||||||
|
const ipAdapterInfo = useAppSelector(
|
||||||
|
(state: RootState) => state.controlNet.ipAdapterInfo
|
||||||
|
);
|
||||||
|
|
||||||
|
const isIPAdapterEnabled = useAppSelector(
|
||||||
|
(state: RootState) => state.controlNet.isIPAdapterEnabled
|
||||||
|
);
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { currentData: imageDTO } = useGetImageDTOQuery(
|
||||||
|
ipAdapterInfo.adapterImage?.image_name ?? skipToken
|
||||||
|
);
|
||||||
|
|
||||||
|
const draggableData = useMemo<TypesafeDraggableData | undefined>(() => {
|
||||||
|
if (imageDTO) {
|
||||||
|
return {
|
||||||
|
id: 'ip-adapter-image',
|
||||||
|
payloadType: 'IMAGE_DTO',
|
||||||
|
payload: { imageDTO },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [imageDTO]);
|
||||||
|
|
||||||
|
const droppableData = useMemo<TypesafeDroppableData | undefined>(
|
||||||
|
() => ({
|
||||||
|
id: 'ip-adapter-image',
|
||||||
|
actionType: 'SET_IP_ADAPTER_IMAGE',
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
position: 'relative',
|
||||||
|
w: 'full',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IAIDndImage
|
||||||
|
imageDTO={imageDTO}
|
||||||
|
droppableData={droppableData}
|
||||||
|
draggableData={draggableData}
|
||||||
|
isUploadDisabled={!isIPAdapterEnabled}
|
||||||
|
dropLabel={t('toast.setIPAdapterImage')}
|
||||||
|
noContentFallback={
|
||||||
|
<IAINoContentFallback
|
||||||
|
label={t('controlnet.ipAdapterImageFallback')}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{ipAdapterInfo.adapterImage && (
|
||||||
|
<IAIIconButton
|
||||||
|
tooltip={t('controlnet.resetIPAdapterImage')}
|
||||||
|
aria-label={t('controlnet.resetIPAdapterImage')}
|
||||||
|
icon={<FaUndo />}
|
||||||
|
onClick={() => dispatch(ipAdapterImageChanged(null))}
|
||||||
|
isDisabled={!imageDTO}
|
||||||
|
size="sm"
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 3,
|
||||||
|
right: 3,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ParamIPAdapterImage);
|
@ -0,0 +1,97 @@
|
|||||||
|
import { SelectItem } from '@mantine/core';
|
||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||||
|
import { ipAdapterModelChanged } from 'features/controlNet/store/controlNetSlice';
|
||||||
|
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
|
||||||
|
import { modelIdToIPAdapterModelParam } from 'features/parameters/util/modelIdToIPAdapterModelParams';
|
||||||
|
import { forEach } from 'lodash-es';
|
||||||
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useGetIPAdapterModelsQuery } from 'services/api/endpoints/models';
|
||||||
|
|
||||||
|
const ParamIPAdapterModelSelect = () => {
|
||||||
|
const ipAdapterModel = useAppSelector(
|
||||||
|
(state: RootState) => state.controlNet.ipAdapterInfo.model
|
||||||
|
);
|
||||||
|
const model = useAppSelector((state: RootState) => state.generation.model);
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { data: ipAdapterModels } = useGetIPAdapterModelsQuery();
|
||||||
|
|
||||||
|
// grab the full model entity from the RTK Query cache
|
||||||
|
const selectedModel = useMemo(
|
||||||
|
() =>
|
||||||
|
ipAdapterModels?.entities[
|
||||||
|
`${ipAdapterModel?.base_model}/ip_adapter/${ipAdapterModel?.model_name}`
|
||||||
|
] ?? null,
|
||||||
|
[
|
||||||
|
ipAdapterModel?.base_model,
|
||||||
|
ipAdapterModel?.model_name,
|
||||||
|
ipAdapterModels?.entities,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = useMemo(() => {
|
||||||
|
if (!ipAdapterModels) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: SelectItem[] = [];
|
||||||
|
|
||||||
|
forEach(ipAdapterModels.entities, (ipAdapterModel, id) => {
|
||||||
|
if (!ipAdapterModel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const disabled = model?.base_model !== ipAdapterModel.base_model;
|
||||||
|
|
||||||
|
data.push({
|
||||||
|
value: id,
|
||||||
|
label: ipAdapterModel.model_name,
|
||||||
|
group: MODEL_TYPE_MAP[ipAdapterModel.base_model],
|
||||||
|
disabled,
|
||||||
|
tooltip: disabled
|
||||||
|
? `Incompatible base model: ${ipAdapterModel.base_model}`
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return data.sort((a, b) => (a.disabled && !b.disabled ? 1 : -1));
|
||||||
|
}, [ipAdapterModels, model?.base_model]);
|
||||||
|
|
||||||
|
const handleValueChanged = useCallback(
|
||||||
|
(v: string | null) => {
|
||||||
|
if (!v) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newIPAdapterModel = modelIdToIPAdapterModelParam(v);
|
||||||
|
|
||||||
|
if (!newIPAdapterModel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(ipAdapterModelChanged(newIPAdapterModel));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAIMantineSelect
|
||||||
|
label={t('controlnet.ipAdapterModel')}
|
||||||
|
className="nowheel nodrag"
|
||||||
|
tooltip={selectedModel?.description}
|
||||||
|
value={selectedModel?.id ?? null}
|
||||||
|
placeholder="Pick one"
|
||||||
|
error={!selectedModel}
|
||||||
|
data={data}
|
||||||
|
onChange={handleValueChanged}
|
||||||
|
sx={{ width: '100%' }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ParamIPAdapterModelSelect);
|
@ -0,0 +1,46 @@
|
|||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAISlider from 'common/components/IAISlider';
|
||||||
|
import { ipAdapterWeightChanged } from 'features/controlNet/store/controlNetSlice';
|
||||||
|
import { memo, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const ParamIPAdapterWeight = () => {
|
||||||
|
const isIpAdapterEnabled = useAppSelector(
|
||||||
|
(state: RootState) => state.controlNet.isIPAdapterEnabled
|
||||||
|
);
|
||||||
|
const ipAdapterWeight = useAppSelector(
|
||||||
|
(state: RootState) => state.controlNet.ipAdapterInfo.weight
|
||||||
|
);
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleWeightChanged = useCallback(
|
||||||
|
(weight: number) => {
|
||||||
|
dispatch(ipAdapterWeightChanged(weight));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleWeightReset = useCallback(() => {
|
||||||
|
dispatch(ipAdapterWeightChanged(1));
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAISlider
|
||||||
|
isDisabled={!isIpAdapterEnabled}
|
||||||
|
label={t('controlnet.weight')}
|
||||||
|
value={ipAdapterWeight}
|
||||||
|
onChange={handleWeightChanged}
|
||||||
|
min={0}
|
||||||
|
max={2}
|
||||||
|
step={0.01}
|
||||||
|
withSliderMarks
|
||||||
|
sliderMarks={[0, 1, 2]}
|
||||||
|
withReset
|
||||||
|
handleReset={handleWeightReset}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ParamIPAdapterWeight);
|
@ -1,9 +1,13 @@
|
|||||||
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||||
import { ControlNetModelParam } from 'features/parameters/types/parameterSchemas';
|
import {
|
||||||
|
ControlNetModelParam,
|
||||||
|
IPAdapterModelParam,
|
||||||
|
} from 'features/parameters/types/parameterSchemas';
|
||||||
import { cloneDeep, forEach } from 'lodash-es';
|
import { cloneDeep, forEach } from 'lodash-es';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
import { components } from 'services/api/schema';
|
import { components } from 'services/api/schema';
|
||||||
import { isAnySessionRejected } from 'services/api/thunks/session';
|
import { isAnySessionRejected } from 'services/api/thunks/session';
|
||||||
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { appSocketInvocationError } from 'services/events/actions';
|
import { appSocketInvocationError } from 'services/events/actions';
|
||||||
import { controlNetImageProcessed } from './actions';
|
import { controlNetImageProcessed } from './actions';
|
||||||
import {
|
import {
|
||||||
@ -56,16 +60,32 @@ export type ControlNetConfig = {
|
|||||||
shouldAutoConfig: boolean;
|
shouldAutoConfig: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type IPAdapterConfig = {
|
||||||
|
adapterImage: ImageDTO | null;
|
||||||
|
model: IPAdapterModelParam | null;
|
||||||
|
weight: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type ControlNetState = {
|
export type ControlNetState = {
|
||||||
controlNets: Record<string, ControlNetConfig>;
|
controlNets: Record<string, ControlNetConfig>;
|
||||||
isEnabled: boolean;
|
isEnabled: boolean;
|
||||||
pendingControlImages: string[];
|
pendingControlImages: string[];
|
||||||
|
isIPAdapterEnabled: boolean;
|
||||||
|
ipAdapterInfo: IPAdapterConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const initialIPAdapterState: IPAdapterConfig = {
|
||||||
|
adapterImage: null,
|
||||||
|
model: null,
|
||||||
|
weight: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initialControlNetState: ControlNetState = {
|
export const initialControlNetState: ControlNetState = {
|
||||||
controlNets: {},
|
controlNets: {},
|
||||||
isEnabled: false,
|
isEnabled: false,
|
||||||
pendingControlImages: [],
|
pendingControlImages: [],
|
||||||
|
isIPAdapterEnabled: false,
|
||||||
|
ipAdapterInfo: { ...initialIPAdapterState },
|
||||||
};
|
};
|
||||||
|
|
||||||
export const controlNetSlice = createSlice({
|
export const controlNetSlice = createSlice({
|
||||||
@ -353,6 +373,25 @@ export const controlNetSlice = createSlice({
|
|||||||
controlNetReset: () => {
|
controlNetReset: () => {
|
||||||
return { ...initialControlNetState };
|
return { ...initialControlNetState };
|
||||||
},
|
},
|
||||||
|
isIPAdapterEnableToggled: (state) => {
|
||||||
|
state.isIPAdapterEnabled = !state.isIPAdapterEnabled;
|
||||||
|
},
|
||||||
|
ipAdapterImageChanged: (state, action: PayloadAction<ImageDTO | null>) => {
|
||||||
|
state.ipAdapterInfo.adapterImage = action.payload;
|
||||||
|
},
|
||||||
|
ipAdapterWeightChanged: (state, action: PayloadAction<number>) => {
|
||||||
|
state.ipAdapterInfo.weight = action.payload;
|
||||||
|
},
|
||||||
|
ipAdapterModelChanged: (
|
||||||
|
state,
|
||||||
|
action: PayloadAction<IPAdapterModelParam | null>
|
||||||
|
) => {
|
||||||
|
state.ipAdapterInfo.model = action.payload;
|
||||||
|
},
|
||||||
|
ipAdapterStateReset: (state) => {
|
||||||
|
state.isIPAdapterEnabled = false;
|
||||||
|
state.ipAdapterInfo = { ...initialIPAdapterState };
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder.addCase(controlNetImageProcessed, (state, action) => {
|
builder.addCase(controlNetImageProcessed, (state, action) => {
|
||||||
@ -412,6 +451,11 @@ export const {
|
|||||||
controlNetProcessorTypeChanged,
|
controlNetProcessorTypeChanged,
|
||||||
controlNetReset,
|
controlNetReset,
|
||||||
controlNetAutoConfigToggled,
|
controlNetAutoConfigToggled,
|
||||||
|
isIPAdapterEnableToggled,
|
||||||
|
ipAdapterImageChanged,
|
||||||
|
ipAdapterWeightChanged,
|
||||||
|
ipAdapterModelChanged,
|
||||||
|
ipAdapterStateReset,
|
||||||
} = controlNetSlice.actions;
|
} = controlNetSlice.actions;
|
||||||
|
|
||||||
export default controlNetSlice.reducer;
|
export default controlNetSlice.reducer;
|
||||||
|
@ -10,20 +10,20 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { some } from 'lodash-es';
|
import { some } from 'lodash-es';
|
||||||
import { ChangeEvent, memo, useCallback, useRef } from 'react';
|
import { ChangeEvent, memo, useCallback, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { imageDeletionConfirmed } from '../store/actions';
|
import { imageDeletionConfirmed } from '../store/actions';
|
||||||
import { getImageUsage, selectImageUsage } from '../store/selectors';
|
import { getImageUsage, selectImageUsage } from '../store/selectors';
|
||||||
import { imageDeletionCanceled, isModalOpenChanged } from '../store/slice';
|
import { imageDeletionCanceled, isModalOpenChanged } from '../store/slice';
|
||||||
import ImageUsageMessage from './ImageUsageMessage';
|
|
||||||
import { ImageUsage } from '../store/types';
|
import { ImageUsage } from '../store/types';
|
||||||
|
import ImageUsageMessage from './ImageUsageMessage';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[stateSelector, selectImageUsage],
|
[stateSelector, selectImageUsage],
|
||||||
@ -42,6 +42,7 @@ const selector = createSelector(
|
|||||||
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
|
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
|
||||||
isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
|
isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
|
||||||
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
|
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
|
||||||
|
isIPAdapterImage: some(allImageUsage, (i) => i.isIPAdapterImage),
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
|
import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
|
||||||
import { some } from 'lodash-es';
|
import { some } from 'lodash-es';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { ImageUsage } from '../store/types';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ImageUsage } from '../store/types';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
imageUsage?: ImageUsage;
|
imageUsage?: ImageUsage;
|
||||||
@ -38,6 +38,9 @@ const ImageUsageMessage = (props: Props) => {
|
|||||||
{imageUsage.isControlNetImage && (
|
{imageUsage.isControlNetImage && (
|
||||||
<ListItem>{t('common.controlNet')}</ListItem>
|
<ListItem>{t('common.controlNet')}</ListItem>
|
||||||
)}
|
)}
|
||||||
|
{imageUsage.isIPAdapterImage && (
|
||||||
|
<ListItem>{t('common.ipAdapter')}</ListItem>
|
||||||
|
)}
|
||||||
{imageUsage.isNodesImage && (
|
{imageUsage.isNodesImage && (
|
||||||
<ListItem>{t('common.nodeEditor')}</ListItem>
|
<ListItem>{t('common.nodeEditor')}</ListItem>
|
||||||
)}
|
)}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
|
import { isInvocationNode } from 'features/nodes/types/types';
|
||||||
import { some } from 'lodash-es';
|
import { some } from 'lodash-es';
|
||||||
import { ImageUsage } from './types';
|
import { ImageUsage } from './types';
|
||||||
import { isInvocationNode } from 'features/nodes/types/types';
|
|
||||||
|
|
||||||
export const getImageUsage = (state: RootState, image_name: string) => {
|
export const getImageUsage = (state: RootState, image_name: string) => {
|
||||||
const { generation, canvas, nodes, controlNet } = state;
|
const { generation, canvas, nodes, controlNet } = state;
|
||||||
@ -27,11 +27,15 @@ export const getImageUsage = (state: RootState, image_name: string) => {
|
|||||||
c.controlImage === image_name || c.processedControlImage === image_name
|
c.controlImage === image_name || c.processedControlImage === image_name
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isIPAdapterImage =
|
||||||
|
controlNet.ipAdapterInfo.adapterImage?.image_name === image_name;
|
||||||
|
|
||||||
const imageUsage: ImageUsage = {
|
const imageUsage: ImageUsage = {
|
||||||
isInitialImage,
|
isInitialImage,
|
||||||
isCanvasImage,
|
isCanvasImage,
|
||||||
isNodesImage,
|
isNodesImage,
|
||||||
isControlNetImage,
|
isControlNetImage,
|
||||||
|
isIPAdapterImage,
|
||||||
};
|
};
|
||||||
|
|
||||||
return imageUsage;
|
return imageUsage;
|
||||||
|
@ -10,4 +10,5 @@ export type ImageUsage = {
|
|||||||
isCanvasImage: boolean;
|
isCanvasImage: boolean;
|
||||||
isNodesImage: boolean;
|
isNodesImage: boolean;
|
||||||
isControlNetImage: boolean;
|
isControlNetImage: boolean;
|
||||||
|
isIPAdapterImage: boolean;
|
||||||
};
|
};
|
||||||
|
@ -35,6 +35,10 @@ export type ControlNetDropData = BaseDropData & {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type IPAdapterImageDropData = BaseDropData & {
|
||||||
|
actionType: 'SET_IP_ADAPTER_IMAGE';
|
||||||
|
};
|
||||||
|
|
||||||
export type CanvasInitialImageDropData = BaseDropData & {
|
export type CanvasInitialImageDropData = BaseDropData & {
|
||||||
actionType: 'SET_CANVAS_INITIAL_IMAGE';
|
actionType: 'SET_CANVAS_INITIAL_IMAGE';
|
||||||
};
|
};
|
||||||
@ -73,6 +77,7 @@ export type TypesafeDroppableData =
|
|||||||
| CurrentImageDropData
|
| CurrentImageDropData
|
||||||
| InitialImageDropData
|
| InitialImageDropData
|
||||||
| ControlNetDropData
|
| ControlNetDropData
|
||||||
|
| IPAdapterImageDropData
|
||||||
| CanvasInitialImageDropData
|
| CanvasInitialImageDropData
|
||||||
| NodesImageDropData
|
| NodesImageDropData
|
||||||
| AddToBatchDropData
|
| AddToBatchDropData
|
||||||
|
@ -24,6 +24,8 @@ export const isValidDrop = (
|
|||||||
return payloadType === 'IMAGE_DTO';
|
return payloadType === 'IMAGE_DTO';
|
||||||
case 'SET_CONTROLNET_IMAGE':
|
case 'SET_CONTROLNET_IMAGE':
|
||||||
return payloadType === 'IMAGE_DTO';
|
return payloadType === 'IMAGE_DTO';
|
||||||
|
case 'SET_IP_ADAPTER_IMAGE':
|
||||||
|
return payloadType === 'IMAGE_DTO';
|
||||||
case 'SET_CANVAS_INITIAL_IMAGE':
|
case 'SET_CANVAS_INITIAL_IMAGE':
|
||||||
return payloadType === 'IMAGE_DTO';
|
return payloadType === 'IMAGE_DTO';
|
||||||
case 'SET_NODES_IMAGE':
|
case 'SET_NODES_IMAGE':
|
||||||
|
@ -53,6 +53,7 @@ const DeleteBoardModal = (props: Props) => {
|
|||||||
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
|
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
|
||||||
isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
|
isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
|
||||||
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
|
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
|
||||||
|
isIPAdapterImage: some(allImageUsage, (i) => i.isIPAdapterImage),
|
||||||
};
|
};
|
||||||
return { imageUsageSummary };
|
return { imageUsageSummary };
|
||||||
}),
|
}),
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { IPAdapterInvocation } from 'services/api/types';
|
||||||
|
import { NonNullableGraph } from '../../types/types';
|
||||||
|
import { IP_ADAPTER } from './constants';
|
||||||
|
|
||||||
|
export const addIPAdapterToLinearGraph = (
|
||||||
|
state: RootState,
|
||||||
|
graph: NonNullableGraph,
|
||||||
|
baseNodeId: string
|
||||||
|
): void => {
|
||||||
|
const { isIPAdapterEnabled, ipAdapterInfo } = state.controlNet;
|
||||||
|
|
||||||
|
// const metadataAccumulator = graph.nodes[METADATA_ACCUMULATOR] as
|
||||||
|
// | MetadataAccumulatorInvocation
|
||||||
|
// | undefined;
|
||||||
|
|
||||||
|
if (isIPAdapterEnabled) {
|
||||||
|
const ipAdapterNode: IPAdapterInvocation = {
|
||||||
|
id: IP_ADAPTER,
|
||||||
|
type: 'ip_adapter',
|
||||||
|
is_intermediate: true,
|
||||||
|
weight: ipAdapterInfo.weight,
|
||||||
|
ip_adapter_model: {
|
||||||
|
base_model: 'sd-1',
|
||||||
|
model_name: 'ip_adapter_plus_sd15',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ipAdapterInfo.adapterImage) {
|
||||||
|
ipAdapterNode.image = {
|
||||||
|
image_name: ipAdapterInfo.adapterImage.image_name,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.nodes[ipAdapterNode.id] = ipAdapterNode as IPAdapterInvocation;
|
||||||
|
|
||||||
|
// if (metadataAccumulator?.ip_adapters) {
|
||||||
|
// // metadata accumulator only needs the ip_adapter field - not the whole node
|
||||||
|
// // extract what we need and add to the accumulator
|
||||||
|
// const ipAdapterField = omit(ipAdapterNode, [
|
||||||
|
// 'id',
|
||||||
|
// 'type',
|
||||||
|
// ]) as IPAdapterField;
|
||||||
|
// metadataAccumulator.ip_adapters.push(ipAdapterField);
|
||||||
|
// }
|
||||||
|
|
||||||
|
graph.edges.push({
|
||||||
|
source: { node_id: ipAdapterNode.id, field: 'ip_adapter' },
|
||||||
|
destination: {
|
||||||
|
node_id: baseNodeId,
|
||||||
|
field: 'ip_adapter',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -5,6 +5,7 @@ import { initialGenerationState } from 'features/parameters/store/generationSlic
|
|||||||
import { ImageDTO, ImageToLatentsInvocation } from 'services/api/types';
|
import { ImageDTO, ImageToLatentsInvocation } from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
||||||
@ -366,6 +367,9 @@ export const buildCanvasImageToImageGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
RangeOfSizeInvocation,
|
RangeOfSizeInvocation,
|
||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
||||||
@ -736,6 +737,9 @@ export const buildCanvasInpaintGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
RangeOfSizeInvocation,
|
RangeOfSizeInvocation,
|
||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
||||||
@ -838,6 +839,9 @@ export const buildCanvasOutpaintGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -5,6 +5,7 @@ import { initialGenerationState } from 'features/parameters/store/generationSlic
|
|||||||
import { ImageDTO, ImageToLatentsInvocation } from 'services/api/types';
|
import { ImageDTO, ImageToLatentsInvocation } from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
||||||
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
||||||
@ -392,6 +393,9 @@ export const buildCanvasSDXLImageToImageGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -46,6 +46,7 @@ import {
|
|||||||
SEAMLESS,
|
SEAMLESS,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
|
import { craftSDXLStylePrompt } from './helpers/craftSDXLStylePrompt';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the Canvas tab's Inpaint graph.
|
* Builds the Canvas tab's Inpaint graph.
|
||||||
@ -765,6 +766,9 @@ export const buildCanvasSDXLInpaintGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
RangeOfSizeInvocation,
|
RangeOfSizeInvocation,
|
||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
||||||
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
||||||
@ -868,6 +869,9 @@ export const buildCanvasSDXLOutpaintGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
||||||
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
||||||
@ -372,6 +373,9 @@ export const buildCanvasSDXLTextToImageGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
||||||
@ -345,6 +346,9 @@ export const buildCanvasTextToImageGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
||||||
@ -364,6 +365,9 @@ export const buildLinearImageToImageGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
||||||
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
||||||
@ -384,6 +385,9 @@ export const buildLinearSDXLImageToImageGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// Add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
// add dynamic prompts - also sets up core iteration and seed
|
// add dynamic prompts - also sets up core iteration and seed
|
||||||
addDynamicPromptsToGraph(state, graph);
|
addDynamicPromptsToGraph(state, graph);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { NonNullableGraph } from 'features/nodes/types/types';
|
|||||||
import { initialGenerationState } from 'features/parameters/store/generationSlice';
|
import { initialGenerationState } from 'features/parameters/store/generationSlice';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
import { addSDXLLoRAsToGraph } from './addSDXLLoRAstoGraph';
|
||||||
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
import { addSDXLRefinerToGraph } from './addSDXLRefinerToGraph';
|
||||||
@ -277,6 +278,9 @@ export const buildLinearSDXLTextToImageGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, SDXL_DENOISE_LATENTS);
|
||||||
|
|
||||||
// add dynamic prompts - also sets up core iteration and seed
|
// add dynamic prompts - also sets up core iteration and seed
|
||||||
addDynamicPromptsToGraph(state, graph);
|
addDynamicPromptsToGraph(state, graph);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
} from 'services/api/types';
|
} from 'services/api/types';
|
||||||
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
import { addControlNetToLinearGraph } from './addControlNetToLinearGraph';
|
||||||
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
import { addDynamicPromptsToGraph } from './addDynamicPromptsToGraph';
|
||||||
|
import { addIPAdapterToLinearGraph } from './addIPAdapterToLinearGraph';
|
||||||
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
import { addLoRAsToGraph } from './addLoRAsToGraph';
|
||||||
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
import { addNSFWCheckerToGraph } from './addNSFWCheckerToGraph';
|
||||||
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
import { addSeamlessToLinearGraph } from './addSeamlessToLinearGraph';
|
||||||
@ -282,6 +283,9 @@ export const buildLinearTextToImageGraph = (
|
|||||||
// add controlnet, mutating `graph`
|
// add controlnet, mutating `graph`
|
||||||
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
addControlNetToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
|
// add IP Adapter
|
||||||
|
addIPAdapterToLinearGraph(state, graph, DENOISE_LATENTS);
|
||||||
|
|
||||||
// NSFW & watermark - must be last thing added to graph
|
// NSFW & watermark - must be last thing added to graph
|
||||||
if (state.system.shouldUseNSFWChecker) {
|
if (state.system.shouldUseNSFWChecker) {
|
||||||
// must add before watermarker!
|
// must add before watermarker!
|
||||||
|
@ -45,6 +45,7 @@ export const MASK_RESIZE_DOWN = 'mask_resize_down';
|
|||||||
export const COLOR_CORRECT = 'color_correct';
|
export const COLOR_CORRECT = 'color_correct';
|
||||||
export const PASTE_IMAGE = 'img_paste';
|
export const PASTE_IMAGE = 'img_paste';
|
||||||
export const CONTROL_NET_COLLECT = 'control_net_collect';
|
export const CONTROL_NET_COLLECT = 'control_net_collect';
|
||||||
|
export const IP_ADAPTER = 'ip_adapter';
|
||||||
export const DYNAMIC_PROMPT = 'dynamic_prompt';
|
export const DYNAMIC_PROMPT = 'dynamic_prompt';
|
||||||
export const IMAGE_COLLECTION = 'image_collection';
|
export const IMAGE_COLLECTION = 'image_collection';
|
||||||
export const IMAGE_COLLECTION_ITERATE = 'image_collection_iterate';
|
export const IMAGE_COLLECTION_ITERATE = 'image_collection_iterate';
|
||||||
|
@ -6,6 +6,7 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import ControlNet from 'features/controlNet/components/ControlNet';
|
import ControlNet from 'features/controlNet/components/ControlNet';
|
||||||
|
import IPAdapterPanel from 'features/controlNet/components/ipAdapter/IPAdapterPanel';
|
||||||
import ParamControlNetFeatureToggle from 'features/controlNet/components/parameters/ParamControlNetFeatureToggle';
|
import ParamControlNetFeatureToggle from 'features/controlNet/components/parameters/ParamControlNetFeatureToggle';
|
||||||
import {
|
import {
|
||||||
controlNetAdded,
|
controlNetAdded,
|
||||||
@ -25,14 +26,23 @@ import { v4 as uuidv4 } from 'uuid';
|
|||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[stateSelector],
|
[stateSelector],
|
||||||
({ controlNet }) => {
|
({ controlNet }) => {
|
||||||
const { controlNets, isEnabled } = controlNet;
|
const { controlNets, isEnabled, isIPAdapterEnabled } = controlNet;
|
||||||
|
|
||||||
const validControlNets = getValidControlNets(controlNets);
|
const validControlNets = getValidControlNets(controlNets);
|
||||||
|
|
||||||
const activeLabel =
|
let activeLabel = undefined;
|
||||||
isEnabled && validControlNets.length > 0
|
|
||||||
? `${validControlNets.length} Active`
|
if (isEnabled && validControlNets.length > 0) {
|
||||||
: undefined;
|
activeLabel = `${validControlNets.length} ControlNet`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isIPAdapterEnabled) {
|
||||||
|
if (activeLabel) {
|
||||||
|
activeLabel = `${activeLabel}, IP Adapter`;
|
||||||
|
} else {
|
||||||
|
activeLabel = 'IP Adapter';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { controlNetsArray: map(controlNets), activeLabel };
|
return { controlNetsArray: map(controlNets), activeLabel };
|
||||||
},
|
},
|
||||||
@ -101,6 +111,7 @@ const ParamControlNetCollapse = () => {
|
|||||||
<ControlNet controlNet={c} />
|
<ControlNet controlNet={c} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
|
<IPAdapterPanel />
|
||||||
</Flex>
|
</Flex>
|
||||||
</IAICollapse>
|
</IAICollapse>
|
||||||
);
|
);
|
||||||
|
@ -339,7 +339,7 @@ export const zIPAdapterModel = z.object({
|
|||||||
/**
|
/**
|
||||||
* Type alias for model parameter, inferred from its zod schema
|
* Type alias for model parameter, inferred from its zod schema
|
||||||
*/
|
*/
|
||||||
export type zIPAdapterModelParam = z.infer<typeof zIPAdapterModel>;
|
export type IPAdapterModelParam = z.infer<typeof zIPAdapterModel>;
|
||||||
/**
|
/**
|
||||||
* Zod schema for l2l strength parameter
|
* Zod schema for l2l strength parameter
|
||||||
*/
|
*/
|
||||||
|
File diff suppressed because one or more lines are too long
@ -63,6 +63,7 @@ export type ControlNetModelField = s['ControlNetModelField'];
|
|||||||
export type IPAdapterModelField = s['IPAdapterModelField'];
|
export type IPAdapterModelField = s['IPAdapterModelField'];
|
||||||
export type ModelsList = s['ModelsList'];
|
export type ModelsList = s['ModelsList'];
|
||||||
export type ControlField = s['ControlField'];
|
export type ControlField = s['ControlField'];
|
||||||
|
export type IPAdapterField = s['IPAdapterField'];
|
||||||
|
|
||||||
// Model Configs
|
// Model Configs
|
||||||
export type LoRAModelConfig = s['LoRAModelConfig'];
|
export type LoRAModelConfig = s['LoRAModelConfig'];
|
||||||
@ -139,6 +140,7 @@ export type SeamlessModeInvocation = s['SeamlessModeInvocation'];
|
|||||||
|
|
||||||
// ControlNet Nodes
|
// ControlNet Nodes
|
||||||
export type ControlNetInvocation = s['ControlNetInvocation'];
|
export type ControlNetInvocation = s['ControlNetInvocation'];
|
||||||
|
export type IPAdapterInvocation = s['IPAdapterInvocation'];
|
||||||
export type CannyImageProcessorInvocation = s['CannyImageProcessorInvocation'];
|
export type CannyImageProcessorInvocation = s['CannyImageProcessorInvocation'];
|
||||||
export type ContentShuffleImageProcessorInvocation =
|
export type ContentShuffleImageProcessorInvocation =
|
||||||
s['ContentShuffleImageProcessorInvocation'];
|
s['ContentShuffleImageProcessorInvocation'];
|
||||||
@ -177,6 +179,10 @@ export type ControlNetAction = {
|
|||||||
controlNetId: string;
|
controlNetId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type IPAdapterAction = {
|
||||||
|
type: 'SET_IP_ADAPTER_IMAGE';
|
||||||
|
};
|
||||||
|
|
||||||
export type InitialImageAction = {
|
export type InitialImageAction = {
|
||||||
type: 'SET_INITIAL_IMAGE';
|
type: 'SET_INITIAL_IMAGE';
|
||||||
};
|
};
|
||||||
@ -202,6 +208,7 @@ export type AddToBatchAction = {
|
|||||||
|
|
||||||
export type PostUploadAction =
|
export type PostUploadAction =
|
||||||
| ControlNetAction
|
| ControlNetAction
|
||||||
|
| IPAdapterAction
|
||||||
| InitialImageAction
|
| InitialImageAction
|
||||||
| NodesAction
|
| NodesAction
|
||||||
| CanvasInitialImageAction
|
| CanvasInitialImageAction
|
||||||
|
Loading…
Reference in New Issue
Block a user