mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
refactor(ui): rip out old control adapter implementation
This commit is contained in:
parent
8864ad1b50
commit
5fc7a03669
@ -4,15 +4,15 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'
|
||||
import type { AppDispatch } from 'app/store/store';
|
||||
import { parseify } from 'common/util/serialize';
|
||||
import {
|
||||
controlAdapterImageChanged,
|
||||
controlAdapterModelChanged,
|
||||
controlAdapterProcessedImageChanged,
|
||||
controlAdapterProcessorConfigChanged,
|
||||
controlAdapterProcessorPendingBatchIdChanged,
|
||||
controlAdapterRecalled,
|
||||
caImageChanged,
|
||||
caModelChanged,
|
||||
caProcessedImageChanged,
|
||||
caProcessorConfigChanged,
|
||||
caProcessorPendingBatchIdChanged,
|
||||
caRecalled,
|
||||
} from 'features/controlLayers/store/canvasV2Slice';
|
||||
import { isControlAdapterLayer } from 'features/controlLayers/store/types';
|
||||
import { CA_PROCESSOR_DATA } from 'features/controlLayers/util/controlAdapters';
|
||||
import { selectCA } from 'features/controlLayers/store/controlAdaptersReducers';
|
||||
import { CA_PROCESSOR_DATA } from 'features/controlLayers/store/types';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import { t } from 'i18next';
|
||||
import { isEqual } from 'lodash-es';
|
||||
@ -22,13 +22,7 @@ import type { BatchConfig } from 'services/api/types';
|
||||
import { socketInvocationComplete } from 'services/events/actions';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
const matcher = isAnyOf(
|
||||
controlAdapterImageChanged,
|
||||
controlAdapterProcessedImageChanged,
|
||||
controlAdapterProcessorConfigChanged,
|
||||
controlAdapterModelChanged,
|
||||
controlAdapterRecalled
|
||||
);
|
||||
const matcher = isAnyOf(caImageChanged, caProcessedImageChanged, caProcessorConfigChanged, caModelChanged, caRecalled);
|
||||
|
||||
const DEBOUNCE_MS = 300;
|
||||
const log = logger('session');
|
||||
@ -36,7 +30,7 @@ const log = logger('session');
|
||||
/**
|
||||
* Simple helper to cancel a batch and reset the pending batch ID
|
||||
*/
|
||||
const cancelProcessorBatch = async (dispatch: AppDispatch, layerId: string, batchId: string) => {
|
||||
const cancelProcessorBatch = async (dispatch: AppDispatch, id: string, batchId: string) => {
|
||||
const req = dispatch(queueApi.endpoints.cancelByBatchIds.initiate({ batch_ids: [batchId] }));
|
||||
log.trace({ batchId }, 'Cancelling existing preprocessor batch');
|
||||
try {
|
||||
@ -46,7 +40,7 @@ const cancelProcessorBatch = async (dispatch: AppDispatch, layerId: string, batc
|
||||
} finally {
|
||||
req.reset();
|
||||
// Always reset the pending batch ID - the cancel req could fail if the batch doesn't exist
|
||||
dispatch(controlAdapterProcessorPendingBatchIdChanged({ layerId, batchId: null }));
|
||||
dispatch(caProcessorPendingBatchIdChanged({ id, batchId: null }));
|
||||
}
|
||||
};
|
||||
|
||||
@ -54,7 +48,7 @@ export const addControlAdapterPreprocessor = (startAppListening: AppStartListeni
|
||||
startAppListening({
|
||||
matcher,
|
||||
effect: async (action, { dispatch, getState, getOriginalState, cancelActiveListeners, delay, take, signal }) => {
|
||||
const layerId = controlAdapterRecalled.match(action) ? action.payload.id : action.payload.layerId;
|
||||
const id = caRecalled.match(action) ? action.payload.data.id : action.payload.id;
|
||||
const state = getState();
|
||||
const originalState = getOriginalState();
|
||||
|
||||
@ -65,22 +59,20 @@ export const addControlAdapterPreprocessor = (startAppListening: AppStartListeni
|
||||
// Delay before starting actual work
|
||||
await delay(DEBOUNCE_MS);
|
||||
|
||||
const layer = state.canvasV2.layers.filter(isControlAdapterLayer).find((l) => l.id === layerId);
|
||||
const ca = selectCA(state.canvasV2, id);
|
||||
|
||||
if (!layer) {
|
||||
if (!ca) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We should only process if the processor settings or image have changed
|
||||
const originalLayer = originalState.canvasV2.layers
|
||||
.filter(isControlAdapterLayer)
|
||||
.find((l) => l.id === layerId);
|
||||
const originalImage = originalLayer?.controlAdapter.image;
|
||||
const originalConfig = originalLayer?.controlAdapter.processorConfig;
|
||||
const originalCA = selectCA(originalState.canvasV2, id);
|
||||
const originalImage = originalCA?.image;
|
||||
const originalConfig = originalCA?.processorConfig;
|
||||
|
||||
const image = layer.controlAdapter.image;
|
||||
const processedImage = layer.controlAdapter.processedImage;
|
||||
const config = layer.controlAdapter.processorConfig;
|
||||
const image = ca.image;
|
||||
const processedImage = ca.processedImage;
|
||||
const config = ca.processorConfig;
|
||||
|
||||
if (isEqual(config, originalConfig) && isEqual(image, originalImage) && processedImage) {
|
||||
// Neither config nor image have changed, we can bail
|
||||
@ -91,15 +83,15 @@ export const addControlAdapterPreprocessor = (startAppListening: AppStartListeni
|
||||
// - If we have no image, we have nothing to process
|
||||
// - If we have no processor config, we have nothing to process
|
||||
// Clear the processed image and bail
|
||||
dispatch(controlAdapterProcessedImageChanged({ layerId, imageDTO: null }));
|
||||
dispatch(caProcessedImageChanged({ id, imageDTO: null }));
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point, the user has stopped fiddling with the processor settings and there is a processor selected.
|
||||
|
||||
// If there is a pending processor batch, cancel it.
|
||||
if (layer.controlAdapter.processorPendingBatchId) {
|
||||
cancelProcessorBatch(dispatch, layerId, layer.controlAdapter.processorPendingBatchId);
|
||||
if (ca.processorPendingBatchId) {
|
||||
cancelProcessorBatch(dispatch, id, ca.processorPendingBatchId);
|
||||
}
|
||||
|
||||
// TODO(psyche): I can't get TS to be happy, it thinkgs `config` is `never` but it should be inferred from the generic... I'll just cast it for now
|
||||
@ -132,7 +124,7 @@ export const addControlAdapterPreprocessor = (startAppListening: AppStartListeni
|
||||
const enqueueResult = await req.unwrap();
|
||||
// TODO(psyche): Update the pydantic models, pretty sure we will _always_ have a batch_id here, but the model says it's optional
|
||||
assert(enqueueResult.batch.batch_id, 'Batch ID not returned from queue');
|
||||
dispatch(controlAdapterProcessorPendingBatchIdChanged({ layerId, batchId: enqueueResult.batch.batch_id }));
|
||||
dispatch(caProcessorPendingBatchIdChanged({ id, batchId: enqueueResult.batch.batch_id }));
|
||||
log.debug({ enqueueResult: parseify(enqueueResult) }, t('queue.graphQueued'));
|
||||
|
||||
// Wait for the processor node to complete
|
||||
@ -154,17 +146,15 @@ export const addControlAdapterPreprocessor = (startAppListening: AppStartListeni
|
||||
assert(imageDTO, "Failed to fetch processor output's image DTO");
|
||||
|
||||
// Whew! We made it. Update the layer with the processed image
|
||||
log.debug({ layerId, imageDTO }, 'ControlNet image processed');
|
||||
dispatch(controlAdapterProcessedImageChanged({ layerId, imageDTO }));
|
||||
dispatch(controlAdapterProcessorPendingBatchIdChanged({ layerId, batchId: null }));
|
||||
log.debug({ id, imageDTO }, 'ControlNet image processed');
|
||||
dispatch(caProcessedImageChanged({ id, imageDTO }));
|
||||
dispatch(caProcessorPendingBatchIdChanged({ id, batchId: null }));
|
||||
} catch (error) {
|
||||
if (signal.aborted) {
|
||||
// The listener was canceled - we need to cancel the pending processor batch, if there is one (could have changed by now).
|
||||
const pendingBatchId = getState()
|
||||
.canvasV2.layers.filter(isControlAdapterLayer)
|
||||
.find((l) => l.id === layerId)?.controlAdapter.processorPendingBatchId;
|
||||
const pendingBatchId = selectCA(getState().canvasV2, id)?.processorPendingBatchId;
|
||||
if (pendingBatchId) {
|
||||
cancelProcessorBatch(dispatch, layerId, pendingBatchId);
|
||||
cancelProcessorBatch(dispatch, id, pendingBatchId);
|
||||
}
|
||||
log.trace('Control Adapter preprocessor cancelled');
|
||||
} else {
|
||||
@ -174,7 +164,7 @@ export const addControlAdapterPreprocessor = (startAppListening: AppStartListeni
|
||||
if (error instanceof Object) {
|
||||
if ('data' in error && 'status' in error) {
|
||||
if (error.status === 403) {
|
||||
dispatch(controlAdapterImageChanged({ layerId, imageDTO: null }));
|
||||
dispatch(caImageChanged({ id, imageDTO: null }));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
import type { AnyListenerPredicate } from '@reduxjs/toolkit';
|
||||
import { logger } from 'app/logging/logger';
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import type { RootState } from 'app/store/store';
|
||||
import { controlAdapterImageProcessed } from 'features/controlAdapters/store/actions';
|
||||
import {
|
||||
controlAdapterAutoConfigToggled,
|
||||
controlAdapterImageChanged,
|
||||
controlAdapterModelChanged,
|
||||
controlAdapterProcessorParamsChanged,
|
||||
controlAdapterProcessortTypeChanged,
|
||||
selectControlAdapterById,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||
|
||||
type AnyControlAdapterParamChangeAction =
|
||||
| ReturnType<typeof controlAdapterProcessorParamsChanged>
|
||||
| ReturnType<typeof controlAdapterModelChanged>
|
||||
| ReturnType<typeof controlAdapterImageChanged>
|
||||
| ReturnType<typeof controlAdapterProcessortTypeChanged>
|
||||
| ReturnType<typeof controlAdapterAutoConfigToggled>;
|
||||
|
||||
const predicate: AnyListenerPredicate<RootState> = (action, state, prevState) => {
|
||||
const isActionMatched =
|
||||
controlAdapterProcessorParamsChanged.match(action) ||
|
||||
controlAdapterModelChanged.match(action) ||
|
||||
controlAdapterImageChanged.match(action) ||
|
||||
controlAdapterProcessortTypeChanged.match(action) ||
|
||||
controlAdapterAutoConfigToggled.match(action);
|
||||
|
||||
if (!isActionMatched) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { id } = action.payload;
|
||||
const prevCA = selectControlAdapterById(prevState.controlAdapters, id);
|
||||
const ca = selectControlAdapterById(state.controlAdapters, id);
|
||||
if (!prevCA || !isControlNetOrT2IAdapter(prevCA) || !ca || !isControlNetOrT2IAdapter(ca)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (controlAdapterAutoConfigToggled.match(action)) {
|
||||
// do not process if the user just disabled auto-config
|
||||
if (prevCA.shouldAutoConfig === true) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const { controlImage, processorType, shouldAutoConfig } = ca;
|
||||
if (controlAdapterModelChanged.match(action) && !shouldAutoConfig) {
|
||||
// do not process if the action is a model change but the processor settings are dirty
|
||||
return false;
|
||||
}
|
||||
|
||||
const isProcessorSelected = processorType !== 'none';
|
||||
|
||||
const hasControlImage = Boolean(controlImage);
|
||||
|
||||
return isProcessorSelected && hasControlImage;
|
||||
};
|
||||
|
||||
const DEBOUNCE_MS = 300;
|
||||
|
||||
/**
|
||||
* Listener that automatically processes a ControlNet image when its processor parameters are changed.
|
||||
*
|
||||
* The network request is debounced.
|
||||
*/
|
||||
export const addControlNetAutoProcessListener = (startAppListening: AppStartListening) => {
|
||||
startAppListening({
|
||||
predicate,
|
||||
effect: async (action, { dispatch, cancelActiveListeners, delay }) => {
|
||||
const log = logger('session');
|
||||
const { id } = (action as AnyControlAdapterParamChangeAction).payload;
|
||||
|
||||
// Cancel any in-progress instances of this listener
|
||||
cancelActiveListeners();
|
||||
log.trace('ControlNet auto-process triggered');
|
||||
// Delay before starting actual work
|
||||
await delay(DEBOUNCE_MS);
|
||||
|
||||
dispatch(controlAdapterImageProcessed({ id }));
|
||||
},
|
||||
});
|
||||
};
|
@ -1,118 +0,0 @@
|
||||
import { logger } from 'app/logging/logger';
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import { parseify } from 'common/util/serialize';
|
||||
import { controlAdapterImageProcessed } from 'features/controlAdapters/store/actions';
|
||||
import {
|
||||
controlAdapterImageChanged,
|
||||
controlAdapterProcessedImageChanged,
|
||||
pendingControlImagesCleared,
|
||||
selectControlAdapterById,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import { t } from 'i18next';
|
||||
import { imagesApi } from 'services/api/endpoints/images';
|
||||
import { queueApi } from 'services/api/endpoints/queue';
|
||||
import type { BatchConfig, ImageDTO } from 'services/api/types';
|
||||
import { socketInvocationComplete } from 'services/events/actions';
|
||||
|
||||
export const addControlNetImageProcessedListener = (startAppListening: AppStartListening) => {
|
||||
startAppListening({
|
||||
actionCreator: controlAdapterImageProcessed,
|
||||
effect: async (action, { dispatch, getState, take }) => {
|
||||
const log = logger('session');
|
||||
const { id } = action.payload;
|
||||
const ca = selectControlAdapterById(getState().controlAdapters, id);
|
||||
|
||||
if (!ca?.controlImage || !isControlNetOrT2IAdapter(ca)) {
|
||||
log.error('Unable to process ControlNet image');
|
||||
return;
|
||||
}
|
||||
|
||||
if (ca.processorType === 'none' || ca.processorNode.type === 'none') {
|
||||
return;
|
||||
}
|
||||
|
||||
// ControlNet one-off procressing graph is just the processor node, no edges.
|
||||
// Also we need to grab the image.
|
||||
|
||||
const nodeId = ca.processorNode.id;
|
||||
const enqueueBatchArg: BatchConfig = {
|
||||
prepend: true,
|
||||
batch: {
|
||||
graph: {
|
||||
nodes: {
|
||||
[ca.processorNode.id]: {
|
||||
...ca.processorNode,
|
||||
is_intermediate: true,
|
||||
use_cache: false,
|
||||
image: { image_name: ca.controlImage },
|
||||
},
|
||||
},
|
||||
edges: [],
|
||||
},
|
||||
runs: 1,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const req = dispatch(
|
||||
queueApi.endpoints.enqueueBatch.initiate(enqueueBatchArg, {
|
||||
fixedCacheKey: 'enqueueBatch',
|
||||
})
|
||||
);
|
||||
const enqueueResult = await req.unwrap();
|
||||
req.reset();
|
||||
log.debug({ enqueueResult: parseify(enqueueResult) }, t('queue.graphQueued'));
|
||||
|
||||
const [invocationCompleteAction] = await take(
|
||||
(action): action is ReturnType<typeof socketInvocationComplete> =>
|
||||
socketInvocationComplete.match(action) &&
|
||||
action.payload.data.batch_id === enqueueResult.batch.batch_id &&
|
||||
action.payload.data.invocation_source_id === nodeId
|
||||
);
|
||||
|
||||
// We still have to check the output type
|
||||
if (invocationCompleteAction.payload.data.result.type === 'image_output') {
|
||||
const { image_name } = invocationCompleteAction.payload.data.result.image;
|
||||
|
||||
// Wait for the ImageDTO to be received
|
||||
const [{ payload }] = await take(
|
||||
(action) =>
|
||||
imagesApi.endpoints.getImageDTO.matchFulfilled(action) && action.payload.image_name === image_name
|
||||
);
|
||||
|
||||
const processedControlImage = payload as ImageDTO;
|
||||
|
||||
log.debug({ controlNetId: action.payload, processedControlImage }, 'ControlNet image processed');
|
||||
|
||||
// Update the processed image in the store
|
||||
dispatch(
|
||||
controlAdapterProcessedImageChanged({
|
||||
id,
|
||||
processedControlImage: processedControlImage.image_name,
|
||||
})
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
log.error({ enqueueBatchArg: parseify(enqueueBatchArg) }, t('queue.graphFailedToQueue'));
|
||||
|
||||
if (error instanceof Object) {
|
||||
if ('data' in error && 'status' in error) {
|
||||
if (error.status === 403) {
|
||||
dispatch(pendingControlImagesCleared());
|
||||
dispatch(controlAdapterImageChanged({ id, controlImage: null }));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toast({
|
||||
id: 'GRAPH_QUEUE_FAILED',
|
||||
title: t('queue.graphFailedToQueue'),
|
||||
status: 'error',
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
@ -1,144 +0,0 @@
|
||||
import { Box, Flex, FormControl, FormLabel, Icon, IconButton, Switch } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import ParamControlAdapterModel from 'features/controlAdapters/components/parameters/ParamControlAdapterModel';
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import { useControlAdapterType } from 'features/controlAdapters/hooks/useControlAdapterType';
|
||||
import {
|
||||
controlAdapterDuplicated,
|
||||
controlAdapterIsEnabledChanged,
|
||||
controlAdapterRemoved,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiCaretUpBold, PiCopyBold, PiTrashSimpleBold } from 'react-icons/pi';
|
||||
import { useToggle } from 'react-use';
|
||||
|
||||
import ControlAdapterImagePreview from './ControlAdapterImagePreview';
|
||||
import ControlAdapterProcessorComponent from './ControlAdapterProcessorComponent';
|
||||
import ControlAdapterShouldAutoConfig from './ControlAdapterShouldAutoConfig';
|
||||
import ControlNetCanvasImageImports from './imports/ControlNetCanvasImageImports';
|
||||
import { ParamControlAdapterBeginEnd } from './parameters/ParamControlAdapterBeginEnd';
|
||||
import ParamControlAdapterControlMode from './parameters/ParamControlAdapterControlMode';
|
||||
import ParamControlAdapterIPMethod from './parameters/ParamControlAdapterIPMethod';
|
||||
import ParamControlAdapterProcessorSelect from './parameters/ParamControlAdapterProcessorSelect';
|
||||
import ParamControlAdapterResizeMode from './parameters/ParamControlAdapterResizeMode';
|
||||
import ParamControlAdapterWeight from './parameters/ParamControlAdapterWeight';
|
||||
|
||||
const ControlAdapterConfig = (props: { id: string; number: number }) => {
|
||||
const { id, number } = props;
|
||||
const controlAdapterType = useControlAdapterType(id);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const [isExpanded, toggleIsExpanded] = useToggle(false);
|
||||
|
||||
const handleDelete = useCallback(() => {
|
||||
dispatch(controlAdapterRemoved({ id }));
|
||||
}, [id, dispatch]);
|
||||
|
||||
const handleDuplicate = useCallback(() => {
|
||||
dispatch(controlAdapterDuplicated(id));
|
||||
}, [id, dispatch]);
|
||||
|
||||
const handleToggleIsEnabled = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(
|
||||
controlAdapterIsEnabledChanged({
|
||||
id,
|
||||
isEnabled: e.target.checked,
|
||||
})
|
||||
);
|
||||
},
|
||||
[id, dispatch]
|
||||
);
|
||||
|
||||
if (!controlAdapterType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" gap={4} p={4} borderRadius="base" position="relative" bg="base.750">
|
||||
<Flex gap={2} alignItems="center" justifyContent="space-between">
|
||||
<FormControl>
|
||||
<FormLabel flexGrow={1}>{t(`controlnet.${controlAdapterType}`, { number })}</FormLabel>
|
||||
<Switch
|
||||
aria-label={t('controlnet.toggleControlNet')}
|
||||
isChecked={isEnabled}
|
||||
onChange={handleToggleIsEnabled}
|
||||
/>
|
||||
</FormControl>
|
||||
</Flex>
|
||||
<Flex gap={4} alignItems="center">
|
||||
<Box minW={0} w="full" transitionProperty="common" transitionDuration="0.1s">
|
||||
<ParamControlAdapterModel id={id} />
|
||||
</Box>
|
||||
{activeTabName === 'canvas' && <ControlNetCanvasImageImports id={id} />}
|
||||
<IconButton
|
||||
size="sm"
|
||||
tooltip={t('controlnet.duplicate')}
|
||||
aria-label={t('controlnet.duplicate')}
|
||||
onClick={handleDuplicate}
|
||||
icon={<PiCopyBold />}
|
||||
/>
|
||||
<IconButton
|
||||
size="sm"
|
||||
tooltip={t('controlnet.delete')}
|
||||
aria-label={t('controlnet.delete')}
|
||||
colorScheme="error"
|
||||
onClick={handleDelete}
|
||||
icon={<PiTrashSimpleBold />}
|
||||
/>
|
||||
<IconButton
|
||||
size="sm"
|
||||
tooltip={isExpanded ? t('controlnet.hideAdvanced') : t('controlnet.showAdvanced')}
|
||||
aria-label={isExpanded ? t('controlnet.hideAdvanced') : t('controlnet.showAdvanced')}
|
||||
onClick={toggleIsExpanded}
|
||||
variant="ghost"
|
||||
icon={
|
||||
<Icon
|
||||
boxSize={4}
|
||||
as={PiCaretUpBold}
|
||||
transform={isExpanded ? 'rotate(0deg)' : 'rotate(180deg)'}
|
||||
transitionProperty="common"
|
||||
transitionDuration="normal"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
<Flex w="full" flexDir="column" gap={4}>
|
||||
<Flex gap={8} w="full" alignItems="center">
|
||||
<Flex flexDir="column" gap={4} h={controlAdapterType === 'ip_adapter' ? 40 : 32} w="full">
|
||||
<ParamControlAdapterIPMethod id={id} />
|
||||
<ParamControlAdapterWeight id={id} />
|
||||
<ParamControlAdapterBeginEnd id={id} />
|
||||
</Flex>
|
||||
{!isExpanded && (
|
||||
<Flex alignItems="center" justifyContent="center" h={32} w={32} aspectRatio="1/1">
|
||||
<ControlAdapterImagePreview id={id} isSmall />
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
{isExpanded && (
|
||||
<>
|
||||
<Flex gap={2}>
|
||||
<ParamControlAdapterControlMode id={id} />
|
||||
<ParamControlAdapterResizeMode id={id} />
|
||||
</Flex>
|
||||
<ParamControlAdapterProcessorSelect id={id} />
|
||||
<ControlAdapterImagePreview id={id} />
|
||||
<ControlAdapterShouldAutoConfig id={id} />
|
||||
<ControlAdapterProcessorComponent id={id} />
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ControlAdapterConfig);
|
@ -1,227 +0,0 @@
|
||||
import { Box, Flex, Spinner } from '@invoke-ai/ui-library';
|
||||
import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||
import { useControlAdapterControlImage } from 'features/controlAdapters/hooks/useControlAdapterControlImage';
|
||||
import { useControlAdapterProcessedControlImage } from 'features/controlAdapters/hooks/useControlAdapterProcessedControlImage';
|
||||
import { useControlAdapterProcessorType } from 'features/controlAdapters/hooks/useControlAdapterProcessorType';
|
||||
import {
|
||||
controlAdapterImageChanged,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { heightChanged, widthChanged } from 'features/controlLayers/store/canvasV2Slice';
|
||||
import type { TypesafeDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
||||
import { calculateNewSize } from 'features/parameters/components/ImageSize/calculateNewSize';
|
||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiArrowCounterClockwiseBold, PiFloppyDiskBold, PiRulerBold } from 'react-icons/pi';
|
||||
import {
|
||||
useAddImageToBoardMutation,
|
||||
useChangeImageIsIntermediateMutation,
|
||||
useGetImageDTOQuery,
|
||||
useRemoveImageFromBoardMutation,
|
||||
} from 'services/api/endpoints/images';
|
||||
import type { PostUploadAction } from 'services/api/types';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
isSmall?: boolean;
|
||||
};
|
||||
|
||||
const selectPendingControlImages = createMemoizedSelector(
|
||||
selectControlAdaptersSlice,
|
||||
(controlAdapters) => controlAdapters.pendingControlImages
|
||||
);
|
||||
|
||||
const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const controlImageName = useControlAdapterControlImage(id);
|
||||
const processedControlImageName = useControlAdapterProcessedControlImage(id);
|
||||
const processorType = useControlAdapterProcessorType(id);
|
||||
const autoAddBoardId = useAppSelector((s) => s.gallery.autoAddBoardId);
|
||||
const isConnected = useAppSelector((s) => s.system.isConnected);
|
||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
||||
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||
const pendingControlImages = useAppSelector(selectPendingControlImages);
|
||||
|
||||
const [isMouseOverImage, setIsMouseOverImage] = useState(false);
|
||||
|
||||
const { currentData: controlImage, isError: isErrorControlImage } = useGetImageDTOQuery(
|
||||
controlImageName ?? skipToken
|
||||
);
|
||||
|
||||
const { currentData: processedControlImage, isError: isErrorProcessedControlImage } = useGetImageDTOQuery(
|
||||
processedControlImageName ?? skipToken
|
||||
);
|
||||
|
||||
const [changeIsIntermediate] = useChangeImageIsIntermediateMutation();
|
||||
const [addToBoard] = useAddImageToBoardMutation();
|
||||
const [removeFromBoard] = useRemoveImageFromBoardMutation();
|
||||
const handleResetControlImage = useCallback(() => {
|
||||
dispatch(controlAdapterImageChanged({ id, controlImage: null }));
|
||||
}, [id, dispatch]);
|
||||
|
||||
const handleSaveControlImage = useCallback(async () => {
|
||||
if (!processedControlImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
await changeIsIntermediate({
|
||||
imageDTO: processedControlImage,
|
||||
is_intermediate: false,
|
||||
}).unwrap();
|
||||
|
||||
if (autoAddBoardId !== 'none') {
|
||||
addToBoard({
|
||||
imageDTO: processedControlImage,
|
||||
board_id: autoAddBoardId,
|
||||
});
|
||||
} else {
|
||||
removeFromBoard({ imageDTO: processedControlImage });
|
||||
}
|
||||
}, [processedControlImage, changeIsIntermediate, autoAddBoardId, addToBoard, removeFromBoard]);
|
||||
|
||||
const handleSetControlImageToDimensions = useCallback(() => {
|
||||
if (!controlImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeTabName === 'canvas') {
|
||||
dispatch(setBoundingBoxDimensions({ width: controlImage.width, height: controlImage.height }, optimalDimension));
|
||||
} else {
|
||||
const options = { updateAspectRatio: true, clamp: true };
|
||||
const { width, height } = calculateNewSize(
|
||||
controlImage.width / controlImage.height,
|
||||
optimalDimension * optimalDimension
|
||||
);
|
||||
dispatch(widthChanged({ width, ...options }));
|
||||
dispatch(heightChanged({ height, ...options }));
|
||||
}
|
||||
}, [controlImage, activeTabName, dispatch, optimalDimension]);
|
||||
|
||||
const handleMouseEnter = useCallback(() => {
|
||||
setIsMouseOverImage(true);
|
||||
}, []);
|
||||
|
||||
const handleMouseLeave = useCallback(() => {
|
||||
setIsMouseOverImage(false);
|
||||
}, []);
|
||||
|
||||
const draggableData = useMemo<TypesafeDraggableData | undefined>(() => {
|
||||
if (controlImage) {
|
||||
return {
|
||||
id,
|
||||
payloadType: 'IMAGE_DTO',
|
||||
payload: { imageDTO: controlImage },
|
||||
};
|
||||
}
|
||||
}, [controlImage, id]);
|
||||
|
||||
const droppableData = useMemo<TypesafeDroppableData | undefined>(
|
||||
() => ({
|
||||
id,
|
||||
actionType: 'SET_CONTROL_ADAPTER_IMAGE',
|
||||
context: { id },
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const postUploadAction = useMemo<PostUploadAction>(() => ({ type: 'SET_CONTROL_ADAPTER_IMAGE', id }), [id]);
|
||||
|
||||
const shouldShowProcessedImage =
|
||||
controlImage &&
|
||||
processedControlImage &&
|
||||
!isMouseOverImage &&
|
||||
!pendingControlImages.includes(id) &&
|
||||
processorType !== 'none';
|
||||
|
||||
useEffect(() => {
|
||||
if (isConnected && (isErrorControlImage || isErrorProcessedControlImage)) {
|
||||
handleResetControlImage();
|
||||
}
|
||||
}, [handleResetControlImage, isConnected, isErrorControlImage, isErrorProcessedControlImage]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
position="relative"
|
||||
w="full"
|
||||
h={isSmall ? 32 : 366} // magic no touch
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<IAIDndImage
|
||||
draggableData={draggableData}
|
||||
droppableData={droppableData}
|
||||
imageDTO={controlImage}
|
||||
isDropDisabled={shouldShowProcessedImage}
|
||||
postUploadAction={postUploadAction}
|
||||
/>
|
||||
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
insetInlineStart={0}
|
||||
w="full"
|
||||
h="full"
|
||||
opacity={shouldShowProcessedImage ? 1 : 0}
|
||||
transitionProperty="common"
|
||||
transitionDuration="normal"
|
||||
pointerEvents="none"
|
||||
>
|
||||
<IAIDndImage
|
||||
draggableData={draggableData}
|
||||
droppableData={droppableData}
|
||||
imageDTO={processedControlImage}
|
||||
isUploadDisabled={true}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{controlImage && (
|
||||
<Flex position="absolute" flexDir="column" top={1} insetInlineEnd={1} gap={1}>
|
||||
<IAIDndImageIcon
|
||||
onClick={handleResetControlImage}
|
||||
icon={<PiArrowCounterClockwiseBold size={16} />}
|
||||
tooltip={t('controlnet.resetControlImage')}
|
||||
/>
|
||||
<IAIDndImageIcon
|
||||
onClick={handleSaveControlImage}
|
||||
icon={<PiFloppyDiskBold size={16} />}
|
||||
tooltip={t('controlnet.saveControlImage')}
|
||||
/>
|
||||
<IAIDndImageIcon
|
||||
onClick={handleSetControlImageToDimensions}
|
||||
icon={<PiRulerBold size={16} />}
|
||||
tooltip={t('controlnet.setControlImageDimensions')}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{pendingControlImages.includes(id) && (
|
||||
<Flex
|
||||
position="absolute"
|
||||
top={0}
|
||||
insetInlineStart={0}
|
||||
w="full"
|
||||
h="full"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
opacity={0.8}
|
||||
borderRadius="base"
|
||||
bg="base.900"
|
||||
>
|
||||
<Spinner size="xl" color="base.400" />
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ControlAdapterImagePreview);
|
@ -1,91 +0,0 @@
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import { useControlAdapterProcessorNode } from 'features/controlAdapters/hooks/useControlAdapterProcessorNode';
|
||||
import { memo } from 'react';
|
||||
|
||||
import CannyProcessor from './processors/CannyProcessor';
|
||||
import ColorMapProcessor from './processors/ColorMapProcessor';
|
||||
import ContentShuffleProcessor from './processors/ContentShuffleProcessor';
|
||||
import DepthAnyThingProcessor from './processors/DepthAnyThingProcessor';
|
||||
import DWOpenposeProcessor from './processors/DWOpenposeProcessor';
|
||||
import HedProcessor from './processors/HedProcessor';
|
||||
import LineartAnimeProcessor from './processors/LineartAnimeProcessor';
|
||||
import LineartProcessor from './processors/LineartProcessor';
|
||||
import MediapipeFaceProcessor from './processors/MediapipeFaceProcessor';
|
||||
import MidasDepthProcessor from './processors/MidasDepthProcessor';
|
||||
import MlsdImageProcessor from './processors/MlsdImageProcessor';
|
||||
import NormalBaeProcessor from './processors/NormalBaeProcessor';
|
||||
import PidiProcessor from './processors/PidiProcessor';
|
||||
import ZoeDepthProcessor from './processors/ZoeDepthProcessor';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const ControlAdapterProcessorComponent = ({ id }: Props) => {
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const processorNode = useControlAdapterProcessorNode(id);
|
||||
|
||||
if (!processorNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'canny_image_processor') {
|
||||
return <CannyProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'color_map_image_processor') {
|
||||
return <ColorMapProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'depth_anything_image_processor') {
|
||||
return <DepthAnyThingProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'hed_image_processor') {
|
||||
return <HedProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'lineart_image_processor') {
|
||||
return <LineartProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'content_shuffle_image_processor') {
|
||||
return <ContentShuffleProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'lineart_anime_image_processor') {
|
||||
return <LineartAnimeProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'mediapipe_face_processor') {
|
||||
return <MediapipeFaceProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'midas_depth_image_processor') {
|
||||
return <MidasDepthProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'mlsd_image_processor') {
|
||||
return <MlsdImageProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'normalbae_image_processor') {
|
||||
return <NormalBaeProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'dw_openpose_image_processor') {
|
||||
return <DWOpenposeProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'pidi_image_processor') {
|
||||
return <PidiProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
if (processorNode.type === 'zoe_depth_image_processor') {
|
||||
return <ZoeDepthProcessor controlNetId={id} processorNode={processorNode} isEnabled={isEnabled} />;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default memo(ControlAdapterProcessorComponent);
|
@ -1,38 +0,0 @@
|
||||
import { FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import { useControlAdapterModel } from 'features/controlAdapters/hooks/useControlAdapterModel';
|
||||
import { useControlAdapterShouldAutoConfig } from 'features/controlAdapters/hooks/useControlAdapterShouldAutoConfig';
|
||||
import { controlAdapterAutoConfigToggled } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isNil } from 'lodash-es';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const ControlAdapterShouldAutoConfig = ({ id }: Props) => {
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const shouldAutoConfig = useControlAdapterShouldAutoConfig(id);
|
||||
const { modelConfig } = useControlAdapterModel(id);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleShouldAutoConfigChanged = useCallback(() => {
|
||||
dispatch(controlAdapterAutoConfigToggled({ id, modelConfig }));
|
||||
}, [id, dispatch, modelConfig]);
|
||||
|
||||
if (isNil(shouldAutoConfig)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel flexGrow={1}>{t('controlnet.autoConfigure')}</FormLabel>
|
||||
<Switch isChecked={shouldAutoConfig} onChange={handleShouldAutoConfigChanged} />
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ControlAdapterShouldAutoConfig);
|
@ -1,20 +0,0 @@
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { controlAdapterProcessorParamsChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import type { ControlAdapterProcessorNode } from 'features/controlAdapters/store/types';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useProcessorNodeChanged = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const handleProcessorNodeChanged = useCallback(
|
||||
(id: string, params: Partial<ControlAdapterProcessorNode>) => {
|
||||
dispatch(
|
||||
controlAdapterProcessorParamsChanged({
|
||||
id,
|
||||
params,
|
||||
})
|
||||
);
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
return handleProcessorNodeChanged;
|
||||
};
|
@ -1,45 +0,0 @@
|
||||
import { Flex, IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { canvasImageToControlAdapter, canvasMaskToControlAdapter } from 'features/canvas/store/actions';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiExcludeBold, PiImageSquareBold } from 'react-icons/pi';
|
||||
|
||||
type ControlNetCanvasImageImportsProps = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const ControlNetCanvasImageImports = (props: ControlNetCanvasImageImportsProps) => {
|
||||
const { id } = props;
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleImportImageFromCanvas = useCallback(() => {
|
||||
dispatch(canvasImageToControlAdapter({ id }));
|
||||
}, [id, dispatch]);
|
||||
|
||||
const handleImportMaskFromCanvas = useCallback(() => {
|
||||
dispatch(canvasMaskToControlAdapter({ id }));
|
||||
}, [id, dispatch]);
|
||||
|
||||
return (
|
||||
<Flex gap={4}>
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={<PiImageSquareBold />}
|
||||
tooltip={t('controlnet.importImageFromCanvas')}
|
||||
aria-label={t('controlnet.importImageFromCanvas')}
|
||||
onClick={handleImportImageFromCanvas}
|
||||
/>
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon={<PiExcludeBold />}
|
||||
tooltip={t('controlnet.importMaskFromCanvas')}
|
||||
aria-label={t('controlnet.importMaskFromCanvas')}
|
||||
onClick={handleImportMaskFromCanvas}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ControlNetCanvasImageImports);
|
@ -1,89 +0,0 @@
|
||||
import { CompositeRangeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useControlAdapterBeginEndStepPct } from 'features/controlAdapters/hooks/useControlAdapterBeginEndStepPct';
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import {
|
||||
controlAdapterBeginStepPctChanged,
|
||||
controlAdapterEndStepPctChanged,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const formatPct = (v: number) => `${Math.round(v * 100)}%`;
|
||||
|
||||
export const ParamControlAdapterBeginEnd = memo(({ id }: Props) => {
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const stepPcts = useControlAdapterBeginEndStepPct(id);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: [number, number]) => {
|
||||
dispatch(
|
||||
controlAdapterBeginStepPctChanged({
|
||||
id,
|
||||
beginStepPct: v[0],
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
controlAdapterEndStepPctChanged({
|
||||
id,
|
||||
endStepPct: v[1],
|
||||
})
|
||||
);
|
||||
},
|
||||
[dispatch, id]
|
||||
);
|
||||
|
||||
const onReset = useCallback(() => {
|
||||
dispatch(
|
||||
controlAdapterBeginStepPctChanged({
|
||||
id,
|
||||
beginStepPct: 0,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
controlAdapterEndStepPctChanged({
|
||||
id,
|
||||
endStepPct: 1,
|
||||
})
|
||||
);
|
||||
}, [dispatch, id]);
|
||||
|
||||
const value = useMemo<[number, number]>(() => [stepPcts?.beginStepPct ?? 0, stepPcts?.endStepPct ?? 1], [stepPcts]);
|
||||
|
||||
if (!stepPcts) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FormControl isDisabled={!isEnabled} orientation="vertical">
|
||||
<InformationalPopover feature="controlNetBeginEnd">
|
||||
<FormLabel>{t('controlnet.beginEndStepPercent')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<CompositeRangeSlider
|
||||
aria-label={ariaLabel}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onReset={onReset}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.05}
|
||||
fineStep={0.01}
|
||||
minStepsBetweenThumbs={1}
|
||||
formatValue={formatPct}
|
||||
marks
|
||||
withThumbTooltip
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
});
|
||||
|
||||
ParamControlAdapterBeginEnd.displayName = 'ParamControlAdapterBeginEnd';
|
||||
|
||||
const ariaLabel = ['Begin Step %', 'End Step %'];
|
@ -1,66 +0,0 @@
|
||||
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useControlAdapterControlMode } from 'features/controlAdapters/hooks/useControlAdapterControlMode';
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import { controlAdapterControlModeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import type { ControlMode } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const ParamControlAdapterControlMode = ({ id }: Props) => {
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const controlMode = useControlAdapterControlMode(id);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const CONTROL_MODE_DATA = useMemo(
|
||||
() => [
|
||||
{ label: t('controlnet.balanced'), value: 'balanced' },
|
||||
{ label: t('controlnet.prompt'), value: 'more_prompt' },
|
||||
{ label: t('controlnet.control'), value: 'more_control' },
|
||||
{ label: t('controlnet.megaControl'), value: 'unbalanced' },
|
||||
],
|
||||
[t]
|
||||
);
|
||||
|
||||
const handleControlModeChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
dispatch(
|
||||
controlAdapterControlModeChanged({
|
||||
id,
|
||||
controlMode: v.value as ControlMode,
|
||||
})
|
||||
);
|
||||
},
|
||||
[id, dispatch]
|
||||
);
|
||||
|
||||
const value = useMemo(
|
||||
() => CONTROL_MODE_DATA.filter((o) => o.value === controlMode)[0],
|
||||
[CONTROL_MODE_DATA, controlMode]
|
||||
);
|
||||
|
||||
if (!controlMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<InformationalPopover feature="controlNetControlMode">
|
||||
<FormLabel>{t('controlnet.controlMode')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<Combobox value={value} options={CONTROL_MODE_DATA} onChange={handleControlModeChange} />
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ParamControlAdapterControlMode);
|
@ -1,63 +0,0 @@
|
||||
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useControlAdapterIPMethod } from 'features/controlAdapters/hooks/useControlAdapterIPMethod';
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import { controlAdapterIPMethodChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import type { IPMethod } from 'features/controlAdapters/store/types';
|
||||
import { isIPMethod } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const ParamControlAdapterIPMethod = ({ id }: Props) => {
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const method = useControlAdapterIPMethod(id);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const options: { label: string; value: IPMethod }[] = useMemo(
|
||||
() => [
|
||||
{ label: t('controlnet.full'), value: 'full' },
|
||||
{ label: `${t('controlnet.style')} (${t('common.beta')})`, value: 'style' },
|
||||
{ label: `${t('controlnet.composition')} (${t('common.beta')})`, value: 'composition' },
|
||||
],
|
||||
[t]
|
||||
);
|
||||
|
||||
const handleIPMethodChanged = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
if (!isIPMethod(v?.value)) {
|
||||
return;
|
||||
}
|
||||
dispatch(
|
||||
controlAdapterIPMethodChanged({
|
||||
id,
|
||||
method: v.value,
|
||||
})
|
||||
);
|
||||
},
|
||||
[id, dispatch]
|
||||
);
|
||||
|
||||
const value = useMemo(() => options.find((o) => o.value === method), [options, method]);
|
||||
|
||||
if (!method) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<InformationalPopover feature="controlNetResizeMode">
|
||||
<FormLabel>{t('controlnet.ipAdapterMethod')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<Combobox value={value} options={options} isDisabled={!isEnabled} onChange={handleIPMethodChanged} />
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ParamControlAdapterIPMethod);
|
@ -1,139 +0,0 @@
|
||||
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
|
||||
import { Combobox, Flex, FormControl, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox';
|
||||
import { useControlAdapterCLIPVisionModel } from 'features/controlAdapters/hooks/useControlAdapterCLIPVisionModel';
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import { useControlAdapterModel } from 'features/controlAdapters/hooks/useControlAdapterModel';
|
||||
import { useControlAdapterModels } from 'features/controlAdapters/hooks/useControlAdapterModels';
|
||||
import { useControlAdapterType } from 'features/controlAdapters/hooks/useControlAdapterType';
|
||||
import {
|
||||
controlAdapterCLIPVisionModelChanged,
|
||||
controlAdapterModelChanged,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import type { CLIPVisionModel } from 'features/controlAdapters/store/types';
|
||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import type {
|
||||
AnyModelConfig,
|
||||
ControlNetModelConfig,
|
||||
IPAdapterModelConfig,
|
||||
T2IAdapterModelConfig,
|
||||
} from 'services/api/types';
|
||||
|
||||
type ParamControlAdapterModelProps = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const selectMainModel = createMemoizedSelector(selectGenerationSlice, (generation) => generation.model);
|
||||
|
||||
const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => {
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const controlAdapterType = useControlAdapterType(id);
|
||||
const { modelConfig } = useControlAdapterModel(id);
|
||||
const dispatch = useAppDispatch();
|
||||
const currentBaseModel = useAppSelector((s) => s.generation.model?.base);
|
||||
const currentCLIPVisionModel = useControlAdapterCLIPVisionModel(id);
|
||||
const mainModel = useAppSelector(selectMainModel);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [modelConfigs, { isLoading }] = useControlAdapterModels(controlAdapterType);
|
||||
|
||||
const _onChange = useCallback(
|
||||
(modelConfig: ControlNetModelConfig | IPAdapterModelConfig | T2IAdapterModelConfig | null) => {
|
||||
if (!modelConfig) {
|
||||
return;
|
||||
}
|
||||
dispatch(
|
||||
controlAdapterModelChanged({
|
||||
id,
|
||||
modelConfig,
|
||||
})
|
||||
);
|
||||
},
|
||||
[dispatch, id]
|
||||
);
|
||||
|
||||
const onCLIPVisionModelChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
if (!v?.value) {
|
||||
return;
|
||||
}
|
||||
dispatch(controlAdapterCLIPVisionModelChanged({ id, clipVisionModel: v.value as CLIPVisionModel }));
|
||||
},
|
||||
[dispatch, id]
|
||||
);
|
||||
|
||||
const selectedModel = useMemo(
|
||||
() => (modelConfig && controlAdapterType ? { ...modelConfig, model_type: controlAdapterType } : null),
|
||||
[controlAdapterType, modelConfig]
|
||||
);
|
||||
|
||||
const getIsDisabled = useCallback(
|
||||
(model: AnyModelConfig): boolean => {
|
||||
const isCompatible = currentBaseModel === model.base;
|
||||
const hasMainModel = Boolean(currentBaseModel);
|
||||
return !hasMainModel || !isCompatible;
|
||||
},
|
||||
[currentBaseModel]
|
||||
);
|
||||
|
||||
const { options, value, onChange, noOptionsMessage } = useGroupedModelCombobox({
|
||||
modelConfigs,
|
||||
onChange: _onChange,
|
||||
selectedModel,
|
||||
getIsDisabled,
|
||||
isLoading,
|
||||
});
|
||||
|
||||
const clipVisionOptions = useMemo<ComboboxOption[]>(
|
||||
() => [
|
||||
{ label: 'ViT-H', value: 'ViT-H' },
|
||||
{ label: 'ViT-G', value: 'ViT-G' },
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const clipVisionModel = useMemo(
|
||||
() => clipVisionOptions.find((o) => o.value === currentCLIPVisionModel),
|
||||
[clipVisionOptions, currentCLIPVisionModel]
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex sx={{ gap: 2 }}>
|
||||
<Tooltip label={selectedModel?.description}>
|
||||
<FormControl
|
||||
isDisabled={!isEnabled}
|
||||
isInvalid={!value || mainModel?.base !== modelConfig?.base}
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
<Combobox
|
||||
options={options}
|
||||
placeholder={t('controlnet.selectModel')}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
noOptionsMessage={noOptionsMessage}
|
||||
/>
|
||||
</FormControl>
|
||||
</Tooltip>
|
||||
{modelConfig?.type === 'ip_adapter' && modelConfig.format === 'checkpoint' && (
|
||||
<FormControl
|
||||
isDisabled={!isEnabled}
|
||||
isInvalid={!value || mainModel?.base !== modelConfig?.base}
|
||||
sx={{ width: 'max-content', minWidth: 28 }}
|
||||
>
|
||||
<Combobox
|
||||
options={clipVisionOptions}
|
||||
placeholder={t('controlnet.selectCLIPVisionModel')}
|
||||
value={clipVisionModel}
|
||||
onChange={onCLIPVisionModelChange}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ParamControlAdapterModel);
|
@ -1,70 +0,0 @@
|
||||
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import { useControlAdapterProcessorNode } from 'features/controlAdapters/hooks/useControlAdapterProcessorNode';
|
||||
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
|
||||
import { controlAdapterProcessortTypeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import type { ControlAdapterProcessorType } from 'features/controlAdapters/store/types';
|
||||
import { configSelector } from 'features/system/store/configSelectors';
|
||||
import { map } from 'lodash-es';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const selectOptions = createMemoizedSelector(configSelector, (config) => {
|
||||
const options: ComboboxOption[] = map(CONTROLNET_PROCESSORS, (p) => ({
|
||||
value: p.type,
|
||||
label: p.label,
|
||||
}))
|
||||
.sort((a, b) =>
|
||||
// sort 'none' to the top
|
||||
a.value === 'none' ? -1 : b.value === 'none' ? 1 : a.label.localeCompare(b.label)
|
||||
)
|
||||
.filter((d) => !config.sd.disabledControlNetProcessors.includes(d.value as ControlAdapterProcessorType));
|
||||
|
||||
return options;
|
||||
});
|
||||
|
||||
const ParamControlAdapterProcessorSelect = ({ id }: Props) => {
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const processorNode = useControlAdapterProcessorNode(id);
|
||||
const dispatch = useAppDispatch();
|
||||
const options = useAppSelector(selectOptions);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
dispatch(
|
||||
controlAdapterProcessortTypeChanged({
|
||||
id,
|
||||
processorType: v.value as ControlAdapterProcessorType, // TODO: need runtime check...
|
||||
})
|
||||
);
|
||||
},
|
||||
[id, dispatch]
|
||||
);
|
||||
const value = useMemo(() => options.find((o) => o.value === processorNode?.type), [options, processorNode]);
|
||||
|
||||
if (!processorNode) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<InformationalPopover feature="controlNetProcessor">
|
||||
<FormLabel>{t('controlnet.processor')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<Combobox value={value} options={options} onChange={onChange} />
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ParamControlAdapterProcessorSelect);
|
@ -1,64 +0,0 @@
|
||||
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import { useControlAdapterResizeMode } from 'features/controlAdapters/hooks/useControlAdapterResizeMode';
|
||||
import { controlAdapterResizeModeChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import type { ResizeMode } from 'features/controlAdapters/store/types';
|
||||
import { isResizeMode } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const ParamControlAdapterResizeMode = ({ id }: Props) => {
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const resizeMode = useControlAdapterResizeMode(id);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const options: { label: string; value: ResizeMode }[] = useMemo(
|
||||
() => [
|
||||
{ label: t('controlnet.resize'), value: 'just_resize' },
|
||||
{ label: t('controlnet.crop'), value: 'crop_resize' },
|
||||
{ label: t('controlnet.fill'), value: 'fill_resize' },
|
||||
{ label: t('controlnet.resizeSimple'), value: 'just_resize_simple' },
|
||||
],
|
||||
[t]
|
||||
);
|
||||
|
||||
const handleResizeModeChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
if (!isResizeMode(v?.value)) {
|
||||
return;
|
||||
}
|
||||
dispatch(
|
||||
controlAdapterResizeModeChanged({
|
||||
id,
|
||||
resizeMode: v.value,
|
||||
})
|
||||
);
|
||||
},
|
||||
[id, dispatch]
|
||||
);
|
||||
|
||||
const value = useMemo(() => options.find((o) => o.value === resizeMode), [options, resizeMode]);
|
||||
|
||||
if (!resizeMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<InformationalPopover feature="controlNetResizeMode">
|
||||
<FormLabel>{t('controlnet.resizeMode')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<Combobox value={value} options={options} isDisabled={!isEnabled} onChange={handleResizeModeChange} />
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ParamControlAdapterResizeMode);
|
@ -1,74 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { useControlAdapterIsEnabled } from 'features/controlAdapters/hooks/useControlAdapterIsEnabled';
|
||||
import { useControlAdapterWeight } from 'features/controlAdapters/hooks/useControlAdapterWeight';
|
||||
import { controlAdapterWeightChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isNil } from 'lodash-es';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type ParamControlAdapterWeightProps = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const formatValue = (v: number) => v.toFixed(2);
|
||||
|
||||
const ParamControlAdapterWeight = ({ id }: ParamControlAdapterWeightProps) => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const isEnabled = useControlAdapterIsEnabled(id);
|
||||
const weight = useControlAdapterWeight(id);
|
||||
const initial = useAppSelector((s) => s.config.sd.ca.weight.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.ca.weight.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.ca.weight.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.ca.weight.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.ca.weight.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.ca.weight.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.ca.weight.fineStep);
|
||||
|
||||
const onChange = useCallback(
|
||||
(weight: number) => {
|
||||
dispatch(controlAdapterWeightChanged({ id, weight }));
|
||||
},
|
||||
[dispatch, id]
|
||||
);
|
||||
|
||||
if (isNil(weight)) {
|
||||
// should never happen
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<InformationalPopover feature="controlNetWeight">
|
||||
<FormLabel>{t('controlnet.weight')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<CompositeSlider
|
||||
value={weight}
|
||||
onChange={onChange}
|
||||
defaultValue={initial}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
marks={marks}
|
||||
formatValue={formatValue}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={weight}
|
||||
onChange={onChange}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
maxW={20}
|
||||
defaultValue={initial}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ParamControlAdapterWeight);
|
||||
|
||||
const marks = [0, 1, 2];
|
@ -1,129 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredCannyImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type CannyProcessorProps = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredCannyImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const CannyProcessor = (props: CannyProcessorProps) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { low_threshold, high_threshold, image_resolution, detect_resolution } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'canny_image_processor'
|
||||
) as RequiredCannyImageProcessorInvocation;
|
||||
|
||||
const handleLowThresholdChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { low_threshold: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleHighThresholdChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { high_threshold: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.lowThreshold')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={low_threshold}
|
||||
onChange={handleLowThresholdChanged}
|
||||
defaultValue={defaults.low_threshold}
|
||||
min={0}
|
||||
max={255}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={low_threshold}
|
||||
onChange={handleLowThresholdChanged}
|
||||
defaultValue={defaults.low_threshold}
|
||||
min={0}
|
||||
max={255}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.highThreshold')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={high_threshold}
|
||||
onChange={handleHighThresholdChanged}
|
||||
defaultValue={defaults.high_threshold}
|
||||
min={0}
|
||||
max={255}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={high_threshold}
|
||||
onChange={handleHighThresholdChanged}
|
||||
defaultValue={defaults.high_threshold}
|
||||
min={0}
|
||||
max={255}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(CannyProcessor);
|
@ -1,58 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredColorMapImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type ColorMapProcessorProps = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredColorMapImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const ColorMapProcessor = (props: ColorMapProcessorProps) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { color_map_tile_size } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'color_map_image_processor'
|
||||
) as RequiredColorMapImageProcessorInvocation;
|
||||
|
||||
const handleColorMapTileSizeChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { color_map_tile_size: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.colorMapTileSize')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={color_map_tile_size}
|
||||
defaultValue={defaults.color_map_tile_size}
|
||||
onChange={handleColorMapTileSizeChanged}
|
||||
min={1}
|
||||
max={256}
|
||||
step={1}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={color_map_tile_size}
|
||||
defaultValue={defaults.color_map_tile_size}
|
||||
onChange={handleColorMapTileSizeChanged}
|
||||
min={1}
|
||||
max={4096}
|
||||
step={1}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ColorMapProcessor);
|
@ -1,118 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredContentShuffleImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredContentShuffleImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const ContentShuffleProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { image_resolution, detect_resolution, w, h, f } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'content_shuffle_image_processor'
|
||||
) as RequiredContentShuffleImageProcessorInvocation;
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleWChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { w: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleHChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { h: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleFChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { f: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
defaultValue={defaults.image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
defaultValue={defaults.image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.w')}</FormLabel>
|
||||
<CompositeSlider value={w} defaultValue={defaults.w} onChange={handleWChanged} min={0} max={4096} marks />
|
||||
<CompositeNumberInput value={w} defaultValue={defaults.w} onChange={handleWChanged} min={0} max={4096} />
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.h')}</FormLabel>
|
||||
<CompositeSlider value={h} defaultValue={defaults.h} onChange={handleHChanged} min={0} max={4096} marks />
|
||||
<CompositeNumberInput value={h} defaultValue={defaults.h} onChange={handleHChanged} min={0} max={4096} />
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.f')}</FormLabel>
|
||||
<CompositeSlider value={f} defaultValue={defaults.f} onChange={handleFChanged} min={0} max={4096} marks />
|
||||
<CompositeNumberInput value={f} defaultValue={defaults.f} onChange={handleFChanged} min={0} max={4096} />
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ContentShuffleProcessor);
|
@ -1,93 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredDWOpenposeImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredDWOpenposeImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const DWOpenposeProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { image_resolution, draw_body, draw_face, draw_hands } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'dw_openpose_image_processor'
|
||||
) as RequiredDWOpenposeImageProcessorInvocation;
|
||||
|
||||
const handleDrawBodyChanged = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
processorChanged(controlNetId, { draw_body: e.target.checked });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleDrawFaceChanged = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
processorChanged(controlNetId, { draw_face: e.target.checked });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleDrawHandsChanged = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
processorChanged(controlNetId, { draw_hands: e.target.checked });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<Flex sx={{ flexDir: 'row', gap: 6 }}>
|
||||
<FormControl isDisabled={!isEnabled} w="max-content">
|
||||
<FormLabel>{t('controlnet.body')}</FormLabel>
|
||||
<Switch defaultChecked={defaults.draw_body} isChecked={draw_body} onChange={handleDrawBodyChanged} />
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled} w="max-content">
|
||||
<FormLabel>{t('controlnet.face')}</FormLabel>
|
||||
<Switch defaultChecked={defaults.draw_face} isChecked={draw_face} onChange={handleDrawFaceChanged} />
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled} w="max-content">
|
||||
<FormLabel>{t('controlnet.hands')}</FormLabel>
|
||||
<Switch defaultChecked={defaults.draw_hands} isChecked={draw_hands} onChange={handleDrawHandsChanged} />
|
||||
</FormControl>
|
||||
</Flex>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(DWOpenposeProcessor);
|
@ -1,102 +0,0 @@
|
||||
import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||
import { Combobox, CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type {
|
||||
DepthAnythingModelSize,
|
||||
RequiredDepthAnythingImageProcessorInvocation,
|
||||
} from 'features/controlAdapters/store/types';
|
||||
import { isDepthAnythingModelSize } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredDepthAnythingImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const DepthAnythingProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { model_size, resolution } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'midas_depth_image_processor'
|
||||
) as RequiredDepthAnythingImageProcessorInvocation;
|
||||
|
||||
const handleModelSizeChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
if (!isDepthAnythingModelSize(v?.value)) {
|
||||
return;
|
||||
}
|
||||
processorChanged(controlNetId, {
|
||||
model_size: v.value,
|
||||
});
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const options: { label: string; value: DepthAnythingModelSize }[] = useMemo(
|
||||
() => [
|
||||
{ label: t('controlnet.depthAnythingSmallV2'), value: 'small_v2' },
|
||||
{ label: t('controlnet.small'), value: 'small' },
|
||||
{ label: t('controlnet.base'), value: 'base' },
|
||||
{ label: t('controlnet.large'), value: 'large' },
|
||||
],
|
||||
[t]
|
||||
);
|
||||
|
||||
const value = useMemo(() => options.filter((o) => o.value === model_size)[0], [options, model_size]);
|
||||
|
||||
const handleResolutionChange = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleResolutionDefaultChange = useCallback(() => {
|
||||
processorChanged(controlNetId, { resolution: 512 });
|
||||
}, [controlNetId, processorChanged]);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.modelSize')}</FormLabel>
|
||||
<Combobox
|
||||
value={value}
|
||||
defaultInputValue={defaults.model_size}
|
||||
options={options}
|
||||
onChange={handleModelSizeChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={resolution}
|
||||
onChange={handleResolutionChange}
|
||||
defaultValue={defaults.resolution}
|
||||
min={64}
|
||||
max={4096}
|
||||
step={64}
|
||||
marks
|
||||
onReset={handleResolutionDefaultChange}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={resolution}
|
||||
onChange={handleResolutionChange}
|
||||
defaultValue={defaults.resolution}
|
||||
min={64}
|
||||
max={4096}
|
||||
step={64}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(DepthAnythingProcessor);
|
@ -1,95 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredHedImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type HedProcessorProps = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredHedImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const HedPreprocessor = (props: HedProcessorProps) => {
|
||||
const {
|
||||
controlNetId,
|
||||
processorNode: { detect_resolution, image_resolution, scribble },
|
||||
isEnabled,
|
||||
} = props;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor('hed_image_processor') as RequiredHedImageProcessorInvocation;
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleScribbleChanged = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
processorChanged(controlNetId, { scribble: e.target.checked });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.scribble')}</FormLabel>
|
||||
<Switch isChecked={scribble} onChange={handleScribbleChanged} />
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(HedPreprocessor);
|
@ -1,82 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredLineartAnimeImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredLineartAnimeImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const LineartAnimeProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { image_resolution, detect_resolution } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'lineart_anime_image_processor'
|
||||
) as RequiredLineartAnimeImageProcessorInvocation;
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(LineartAnimeProcessor);
|
@ -1,94 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredLineartImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type LineartProcessorProps = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredLineartImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const LineartProcessor = (props: LineartProcessorProps) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { image_resolution, detect_resolution, coarse } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'lineart_image_processor'
|
||||
) as RequiredLineartImageProcessorInvocation;
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleCoarseChanged = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
processorChanged(controlNetId, { coarse: e.target.checked });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.coarse')}</FormLabel>
|
||||
<Switch isChecked={coarse} onChange={handleCoarseChanged} />
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(LineartProcessor);
|
@ -1,134 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredMediapipeFaceProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredMediapipeFaceProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const MediapipeFaceProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { max_faces, min_confidence, image_resolution, detect_resolution } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'mediapipe_face_processor'
|
||||
) as RequiredMediapipeFaceProcessorInvocation;
|
||||
|
||||
const handleMaxFacesChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { max_faces: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleMinConfidenceChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { min_confidence: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.maxFaces')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={max_faces}
|
||||
onChange={handleMaxFacesChanged}
|
||||
defaultValue={defaults.max_faces}
|
||||
min={1}
|
||||
max={20}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={max_faces}
|
||||
onChange={handleMaxFacesChanged}
|
||||
defaultValue={defaults.max_faces}
|
||||
min={1}
|
||||
max={20}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.minConfidence')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={min_confidence}
|
||||
onChange={handleMinConfidenceChanged}
|
||||
defaultValue={defaults.min_confidence}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={min_confidence}
|
||||
onChange={handleMinConfidenceChanged}
|
||||
defaultValue={defaults.min_confidence}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(MediapipeFaceProcessor);
|
@ -1,136 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredMidasDepthImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredMidasDepthImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const MidasDepthProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { a_mult, bg_th, image_resolution, detect_resolution } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'midas_depth_image_processor'
|
||||
) as RequiredMidasDepthImageProcessorInvocation;
|
||||
|
||||
const handleAMultChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { a_mult: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleBgThChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { bg_th: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.amult')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={a_mult}
|
||||
onChange={handleAMultChanged}
|
||||
defaultValue={defaults.a_mult}
|
||||
min={0}
|
||||
max={20}
|
||||
step={0.01}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={a_mult}
|
||||
onChange={handleAMultChanged}
|
||||
defaultValue={defaults.a_mult}
|
||||
min={0}
|
||||
max={20}
|
||||
step={0.01}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.bgth')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={bg_th}
|
||||
onChange={handleBgThChanged}
|
||||
defaultValue={defaults.bg_th}
|
||||
min={0}
|
||||
max={20}
|
||||
step={0.01}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={bg_th}
|
||||
onChange={handleBgThChanged}
|
||||
defaultValue={defaults.bg_th}
|
||||
min={0}
|
||||
max={20}
|
||||
step={0.01}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(MidasDepthProcessor);
|
@ -1,137 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredMlsdImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredMlsdImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const MlsdImageProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { image_resolution, detect_resolution, thr_d, thr_v } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor('mlsd_image_processor') as RequiredMlsdImageProcessorInvocation;
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleThrDChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { thr_d: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleThrVChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { thr_v: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks={marks0to4096}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks={marks0to4096}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.w')} </FormLabel>
|
||||
<CompositeSlider
|
||||
value={thr_d}
|
||||
onChange={handleThrDChanged}
|
||||
defaultValue={defaults.thr_d}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
marks={marks0to1}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={thr_d}
|
||||
onChange={handleThrDChanged}
|
||||
defaultValue={defaults.thr_d}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.h')} </FormLabel>
|
||||
<CompositeSlider
|
||||
value={thr_v}
|
||||
onChange={handleThrVChanged}
|
||||
defaultValue={defaults.thr_v}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
marks={marks0to1}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={thr_v}
|
||||
onChange={handleThrVChanged}
|
||||
defaultValue={defaults.thr_v}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(MlsdImageProcessor);
|
||||
|
||||
const marks0to4096 = [0, 4096];
|
||||
const marks0to1 = [0, 1];
|
@ -1,82 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredNormalbaeImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredNormalbaeImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const NormalBaeProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { image_resolution, detect_resolution } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor(
|
||||
'normalbae_image_processor'
|
||||
) as RequiredNormalbaeImageProcessorInvocation;
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(NormalBaeProcessor);
|
@ -1,103 +0,0 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel, Switch } from '@invoke-ai/ui-library';
|
||||
import { useProcessorNodeChanged } from 'features/controlAdapters/components/hooks/useProcessorNodeChanged';
|
||||
import { useGetDefaultForControlnetProcessor } from 'features/controlAdapters/hooks/useGetDefaultForControlnetProcessor';
|
||||
import type { RequiredPidiImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import ProcessorWrapper from './common/ProcessorWrapper';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredPidiImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const PidiProcessor = (props: Props) => {
|
||||
const { controlNetId, processorNode, isEnabled } = props;
|
||||
const { image_resolution, detect_resolution, scribble, safe } = processorNode;
|
||||
const processorChanged = useProcessorNodeChanged();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaults = useGetDefaultForControlnetProcessor('pidi_image_processor') as RequiredPidiImageProcessorInvocation;
|
||||
|
||||
const handleDetectResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { detect_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleImageResolutionChanged = useCallback(
|
||||
(v: number) => {
|
||||
processorChanged(controlNetId, { image_resolution: v });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleScribbleChanged = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
processorChanged(controlNetId, { scribble: e.target.checked });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
const handleSafeChanged = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
processorChanged(controlNetId, { safe: e.target.checked });
|
||||
},
|
||||
[controlNetId, processorChanged]
|
||||
);
|
||||
|
||||
return (
|
||||
<ProcessorWrapper>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.detectResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={detect_resolution}
|
||||
onChange={handleDetectResolutionChanged}
|
||||
defaultValue={defaults.detect_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.imageResolution')}</FormLabel>
|
||||
<CompositeSlider
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={image_resolution}
|
||||
onChange={handleImageResolutionChanged}
|
||||
defaultValue={defaults.image_resolution}
|
||||
min={0}
|
||||
max={4096}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.scribble')}</FormLabel>
|
||||
<Switch isChecked={scribble} onChange={handleScribbleChanged} />
|
||||
</FormControl>
|
||||
<FormControl isDisabled={!isEnabled}>
|
||||
<FormLabel>{t('controlnet.safe')}</FormLabel>
|
||||
<Switch isChecked={safe} onChange={handleSafeChanged} />
|
||||
</FormControl>
|
||||
</ProcessorWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(PidiProcessor);
|
@ -1,15 +0,0 @@
|
||||
import type { RequiredZoeDepthImageProcessorInvocation } from 'features/controlAdapters/store/types';
|
||||
import { memo } from 'react';
|
||||
|
||||
type Props = {
|
||||
controlNetId: string;
|
||||
processorNode: RequiredZoeDepthImageProcessorInvocation;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
|
||||
const ZoeDepthProcessor = (_props: Props) => {
|
||||
// Has no parameters?
|
||||
return null;
|
||||
};
|
||||
|
||||
export default memo(ZoeDepthProcessor);
|
@ -1,15 +0,0 @@
|
||||
import { Flex } from '@invoke-ai/ui-library';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { memo } from 'react';
|
||||
|
||||
type Props = PropsWithChildren;
|
||||
|
||||
const ProcessorWrapper = (props: Props) => {
|
||||
return (
|
||||
<Flex flexDir="column" gap={4}>
|
||||
{props.children}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ProcessorWrapper);
|
@ -1,61 +0,0 @@
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useControlAdapterModels } from 'features/controlAdapters/hooks/useControlAdapterModels';
|
||||
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
|
||||
import { controlAdapterAdded } from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { type ControlAdapterType, isControlAdapterProcessorType } from 'features/controlAdapters/store/types';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import type { ControlNetModelConfig, IPAdapterModelConfig, T2IAdapterModelConfig } from 'services/api/types';
|
||||
|
||||
export const useAddControlAdapter = (type: ControlAdapterType) => {
|
||||
const baseModel = useAppSelector((s) => s.generation.model?.base);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [models] = useControlAdapterModels(type);
|
||||
|
||||
const firstModel: ControlNetModelConfig | T2IAdapterModelConfig | IPAdapterModelConfig | undefined = useMemo(() => {
|
||||
// prefer to use a model that matches the base model
|
||||
const firstCompatibleModel = models.filter((m) => (baseModel ? m.base === baseModel : true))[0];
|
||||
|
||||
if (firstCompatibleModel) {
|
||||
return firstCompatibleModel;
|
||||
}
|
||||
|
||||
return models[0];
|
||||
}, [baseModel, models]);
|
||||
|
||||
const isDisabled = useMemo(() => !firstModel, [firstModel]);
|
||||
|
||||
const addControlAdapter = useCallback(() => {
|
||||
if (isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(type === 'controlnet' || type === 't2i_adapter') &&
|
||||
(firstModel?.type === 'controlnet' || firstModel?.type === 't2i_adapter')
|
||||
) {
|
||||
const defaultPreprocessor = firstModel.default_settings?.preprocessor;
|
||||
const processorType = isControlAdapterProcessorType(defaultPreprocessor) ? defaultPreprocessor : 'none';
|
||||
const processorNode = CONTROLNET_PROCESSORS[processorType].buildDefaults(baseModel);
|
||||
dispatch(
|
||||
controlAdapterAdded({
|
||||
type,
|
||||
overrides: {
|
||||
model: firstModel,
|
||||
processorType,
|
||||
processorNode,
|
||||
},
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
dispatch(
|
||||
controlAdapterAdded({
|
||||
type,
|
||||
overrides: { model: firstModel },
|
||||
})
|
||||
);
|
||||
}, [dispatch, firstModel, isDisabled, type, baseModel]);
|
||||
|
||||
return [addControlAdapter, isDisabled] as const;
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterBeginEndStepPct = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const cn = selectControlAdapterById(controlAdapters, id);
|
||||
return cn
|
||||
? {
|
||||
beginStepPct: cn.beginStepPct,
|
||||
endStepPct: cn.endStepPct,
|
||||
}
|
||||
: undefined;
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const stepPcts = useAppSelector(selector);
|
||||
|
||||
return stepPcts;
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterCLIPVisionModel = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const cn = selectControlAdapterById(controlAdapters, id);
|
||||
if (cn && cn?.type === 'ip_adapter') {
|
||||
return cn.clipVisionModel;
|
||||
}
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const clipVisionModel = useAppSelector(selector);
|
||||
|
||||
return clipVisionModel;
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterControlImage = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
selectControlAdaptersSlice,
|
||||
(controlAdapters) => selectControlAdapterById(controlAdapters, id)?.controlImage
|
||||
),
|
||||
[id]
|
||||
);
|
||||
|
||||
const controlImageName = useAppSelector(selector);
|
||||
|
||||
return controlImageName;
|
||||
};
|
@ -1,26 +0,0 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isControlNet } from 'features/controlAdapters/store/types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterControlMode = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const ca = selectControlAdapterById(controlAdapters, id);
|
||||
if (ca && isControlNet(ca)) {
|
||||
return ca.controlMode;
|
||||
}
|
||||
return undefined;
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const controlMode = useAppSelector(selector);
|
||||
|
||||
return controlMode;
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterIPMethod = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const cn = selectControlAdapterById(controlAdapters, id);
|
||||
if (cn && cn?.type === 'ip_adapter') {
|
||||
return cn.method;
|
||||
}
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const method = useAppSelector(selector);
|
||||
|
||||
return method;
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterIsEnabled = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
selectControlAdaptersSlice,
|
||||
(controlAdapters) => selectControlAdapterById(controlAdapters, id)?.isEnabled ?? false
|
||||
),
|
||||
[id]
|
||||
);
|
||||
|
||||
const isEnabled = useAppSelector(selector);
|
||||
|
||||
return isEnabled;
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { useMemo } from 'react';
|
||||
import { useGetModelConfigWithTypeGuard } from 'services/api/hooks/useGetModelConfigWithTypeGuard';
|
||||
import { isControlAdapterModelConfig } from 'services/api/types';
|
||||
|
||||
export const useControlAdapterModel = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(
|
||||
selectControlAdaptersSlice,
|
||||
(controlAdapters) => selectControlAdapterById(controlAdapters, id)?.model?.key
|
||||
),
|
||||
[id]
|
||||
);
|
||||
|
||||
const key = useAppSelector(selector);
|
||||
|
||||
const result = useGetModelConfigWithTypeGuard(key ?? skipToken, isControlAdapterModelConfig);
|
||||
|
||||
return result;
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
import type { ControlAdapterType } from 'features/controlAdapters/store/types';
|
||||
import { useControlNetModels, useIPAdapterModels, useT2IAdapterModels } from 'services/api/hooks/modelsByType';
|
||||
|
||||
export const useControlAdapterModels = (type: ControlAdapterType) => {
|
||||
const controlNetModels = useControlNetModels();
|
||||
const t2iAdapterModels = useT2IAdapterModels();
|
||||
const ipAdapterModels = useIPAdapterModels();
|
||||
|
||||
if (type === 'controlnet') {
|
||||
return controlNetModels;
|
||||
}
|
||||
if (type === 't2i_adapter') {
|
||||
return t2iAdapterModels;
|
||||
}
|
||||
if (type === 'ip_adapter') {
|
||||
return ipAdapterModels;
|
||||
}
|
||||
|
||||
// Assert that the end of the function is not reachable.
|
||||
const exhaustiveCheck: never = type;
|
||||
return exhaustiveCheck;
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterProcessedControlImage = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const ca = selectControlAdapterById(controlAdapters, id);
|
||||
|
||||
return ca && isControlNetOrT2IAdapter(ca) ? ca.processedControlImage : undefined;
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const weight = useAppSelector(selector);
|
||||
|
||||
return weight;
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterProcessorNode = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const ca = selectControlAdapterById(controlAdapters, id);
|
||||
|
||||
return ca && isControlNetOrT2IAdapter(ca) ? ca.processorNode : undefined;
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const processorNode = useAppSelector(selector);
|
||||
|
||||
return processorNode;
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterProcessorType = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const ca = selectControlAdapterById(controlAdapters, id);
|
||||
|
||||
return ca && isControlNetOrT2IAdapter(ca) ? ca.processorType : undefined;
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const processorType = useAppSelector(selector);
|
||||
|
||||
return processorType;
|
||||
};
|
@ -1,26 +0,0 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterResizeMode = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const ca = selectControlAdapterById(controlAdapters, id);
|
||||
if (ca && isControlNetOrT2IAdapter(ca)) {
|
||||
return ca.resizeMode;
|
||||
}
|
||||
return undefined;
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const controlMode = useAppSelector(selector);
|
||||
|
||||
return controlMode;
|
||||
};
|
@ -1,26 +0,0 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterShouldAutoConfig = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const ca = selectControlAdapterById(controlAdapters, id);
|
||||
if (ca && isControlNetOrT2IAdapter(ca)) {
|
||||
return ca.shouldAutoConfig;
|
||||
}
|
||||
return undefined;
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const controlMode = useAppSelector(selector);
|
||||
|
||||
return controlMode;
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { useMemo } from 'react';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
export const useControlAdapterType = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||
const type = selectControlAdapterById(controlAdapters, id)?.type;
|
||||
assert(type !== undefined, `Control adapter with id ${id} not found`);
|
||||
return type;
|
||||
}),
|
||||
[id]
|
||||
);
|
||||
|
||||
const type = useAppSelector(selector);
|
||||
|
||||
return type;
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
selectControlAdapterById,
|
||||
selectControlAdaptersSlice,
|
||||
} from 'features/controlAdapters/store/controlAdaptersSlice';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useControlAdapterWeight = (id: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
selectControlAdaptersSlice,
|
||||
(controlAdapters) => selectControlAdapterById(controlAdapters, id)?.weight
|
||||
),
|
||||
[id]
|
||||
);
|
||||
|
||||
const weight = useAppSelector(selector);
|
||||
|
||||
return weight;
|
||||
};
|
@ -1,14 +0,0 @@
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
|
||||
import type { ControlAdapterProcessorType } from 'features/controlAdapters/store/types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useGetDefaultForControlnetProcessor = (processorType: ControlAdapterProcessorType) => {
|
||||
const baseModel = useAppSelector((s) => s.generation.model?.base);
|
||||
|
||||
const defaults = useMemo(() => {
|
||||
return CONTROLNET_PROCESSORS[processorType].buildDefaults(baseModel);
|
||||
}, [baseModel, processorType]);
|
||||
|
||||
return defaults;
|
||||
};
|
@ -1,5 +0,0 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
export const controlAdapterImageProcessed = createAction<{
|
||||
id: string;
|
||||
}>('controlAdapters/imageProcessed');
|
@ -1,261 +0,0 @@
|
||||
import i18n from 'i18next';
|
||||
import type { BaseModelType } from 'services/api/types';
|
||||
|
||||
import type { ControlAdapterProcessorType, RequiredControlAdapterProcessorNode } from './types';
|
||||
|
||||
type ControlNetProcessorsDict = Record<
|
||||
ControlAdapterProcessorType,
|
||||
{
|
||||
type: ControlAdapterProcessorType | 'none';
|
||||
label: string;
|
||||
description: string;
|
||||
buildDefaults(baseModel?: BaseModelType): RequiredControlAdapterProcessorNode | { type: 'none' };
|
||||
}
|
||||
>;
|
||||
/**
|
||||
* A dict of ControlNet processors, including:
|
||||
* - type
|
||||
* - label
|
||||
* - description
|
||||
* - default values
|
||||
*
|
||||
* TODO: Generate from the OpenAPI schema
|
||||
*/
|
||||
export const CONTROLNET_PROCESSORS: ControlNetProcessorsDict = {
|
||||
none: {
|
||||
type: 'none',
|
||||
get label() {
|
||||
return i18n.t('controlnet.none');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.noneDescription');
|
||||
},
|
||||
buildDefaults: () => ({
|
||||
type: 'none',
|
||||
}),
|
||||
},
|
||||
canny_image_processor: {
|
||||
type: 'canny_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.canny');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.cannyDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'canny_image_processor',
|
||||
type: 'canny_image_processor',
|
||||
low_threshold: 100,
|
||||
high_threshold: 200,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
}),
|
||||
},
|
||||
color_map_image_processor: {
|
||||
type: 'color_map_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.colorMap');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.colorMapDescription');
|
||||
},
|
||||
buildDefaults: () => ({
|
||||
id: 'color_map_image_processor',
|
||||
type: 'color_map_image_processor',
|
||||
color_map_tile_size: 64,
|
||||
}),
|
||||
},
|
||||
content_shuffle_image_processor: {
|
||||
type: 'content_shuffle_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.contentShuffle');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.contentShuffleDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'content_shuffle_image_processor',
|
||||
type: 'content_shuffle_image_processor',
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
h: baseModel === 'sdxl' ? 1024 : 512,
|
||||
w: baseModel === 'sdxl' ? 1024 : 512,
|
||||
f: baseModel === 'sdxl' ? 512 : 256,
|
||||
}),
|
||||
},
|
||||
depth_anything_image_processor: {
|
||||
type: 'depth_anything_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.depthAnything');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.depthAnythingDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'depth_anything_image_processor',
|
||||
type: 'depth_anything_image_processor',
|
||||
model_size: 'small_v2',
|
||||
resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
}),
|
||||
},
|
||||
hed_image_processor: {
|
||||
type: 'hed_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.hed');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.hedDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'hed_image_processor',
|
||||
type: 'hed_image_processor',
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
scribble: false,
|
||||
}),
|
||||
},
|
||||
lineart_anime_image_processor: {
|
||||
type: 'lineart_anime_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.lineartAnime');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.lineartAnimeDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'lineart_anime_image_processor',
|
||||
type: 'lineart_anime_image_processor',
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
}),
|
||||
},
|
||||
lineart_image_processor: {
|
||||
type: 'lineart_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.lineart');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.lineartDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'lineart_image_processor',
|
||||
type: 'lineart_image_processor',
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
coarse: false,
|
||||
}),
|
||||
},
|
||||
mediapipe_face_processor: {
|
||||
type: 'mediapipe_face_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.mediapipeFace');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.mediapipeFaceDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'mediapipe_face_processor',
|
||||
type: 'mediapipe_face_processor',
|
||||
max_faces: 1,
|
||||
min_confidence: 0.5,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
}),
|
||||
},
|
||||
midas_depth_image_processor: {
|
||||
type: 'midas_depth_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.depthMidas');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.depthMidasDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'midas_depth_image_processor',
|
||||
type: 'midas_depth_image_processor',
|
||||
a_mult: 2,
|
||||
bg_th: 0.1,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
}),
|
||||
},
|
||||
mlsd_image_processor: {
|
||||
type: 'mlsd_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.mlsd');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.mlsdDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'mlsd_image_processor',
|
||||
type: 'mlsd_image_processor',
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
thr_d: 0.1,
|
||||
thr_v: 0.1,
|
||||
}),
|
||||
},
|
||||
normalbae_image_processor: {
|
||||
type: 'normalbae_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.normalBae');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.normalBaeDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'normalbae_image_processor',
|
||||
type: 'normalbae_image_processor',
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
}),
|
||||
},
|
||||
dw_openpose_image_processor: {
|
||||
type: 'dw_openpose_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.dwOpenpose');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.dwOpenposeDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'dw_openpose_image_processor',
|
||||
type: 'dw_openpose_image_processor',
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
draw_body: true,
|
||||
draw_face: false,
|
||||
draw_hands: false,
|
||||
}),
|
||||
},
|
||||
pidi_image_processor: {
|
||||
type: 'pidi_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.pidi');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.pidiDescription');
|
||||
},
|
||||
buildDefaults: (baseModel?: BaseModelType) => ({
|
||||
id: 'pidi_image_processor',
|
||||
type: 'pidi_image_processor',
|
||||
detect_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
image_resolution: baseModel === 'sdxl' ? 1024 : 512,
|
||||
scribble: false,
|
||||
safe: false,
|
||||
}),
|
||||
},
|
||||
zoe_depth_image_processor: {
|
||||
type: 'zoe_depth_image_processor',
|
||||
get label() {
|
||||
return i18n.t('controlnet.depthZoe');
|
||||
},
|
||||
get description() {
|
||||
return i18n.t('controlnet.depthZoeDescription');
|
||||
},
|
||||
buildDefaults: () => ({
|
||||
id: 'zoe_depth_image_processor',
|
||||
type: 'zoe_depth_image_processor',
|
||||
}),
|
||||
},
|
||||
};
|
@ -1,433 +0,0 @@
|
||||
import type { PayloadAction, Update } from '@reduxjs/toolkit';
|
||||
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit';
|
||||
import { getSelectorsOptions } from 'app/store/createMemoizedSelector';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import { buildControlAdapter } from 'features/controlAdapters/util/buildControlAdapter';
|
||||
import { buildControlAdapterProcessor } from 'features/controlAdapters/util/buildControlAdapterProcessor';
|
||||
import { zModelIdentifierField } from 'features/nodes/types/common';
|
||||
import { merge, uniq } from 'lodash-es';
|
||||
import type { ControlNetModelConfig, IPAdapterModelConfig, T2IAdapterModelConfig } from 'services/api/types';
|
||||
import { socketInvocationError } from 'services/events/actions';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { controlAdapterImageProcessed } from './actions';
|
||||
import { CONTROLNET_PROCESSORS } from './constants';
|
||||
import type {
|
||||
CLIPVisionModel,
|
||||
ControlAdapterConfig,
|
||||
ControlAdapterProcessorType,
|
||||
ControlAdaptersState,
|
||||
ControlAdapterType,
|
||||
ControlMode,
|
||||
ControlNetConfig,
|
||||
IPMethod,
|
||||
RequiredControlAdapterProcessorNode,
|
||||
ResizeMode,
|
||||
T2IAdapterConfig,
|
||||
} from './types';
|
||||
import { isControlNet, isControlNetOrT2IAdapter, isIPAdapter, isT2IAdapter } from './types';
|
||||
|
||||
const caAdapter = createEntityAdapter<ControlAdapterConfig, string>({
|
||||
selectId: (ca) => ca.id,
|
||||
});
|
||||
const caAdapterSelectors = caAdapter.getSelectors(undefined, getSelectorsOptions);
|
||||
|
||||
export const {
|
||||
selectById: selectControlAdapterById,
|
||||
selectAll: selectControlAdapterAll,
|
||||
selectIds: selectControlAdapterIds,
|
||||
} = caAdapterSelectors;
|
||||
|
||||
const initialControlAdaptersState: ControlAdaptersState = caAdapter.getInitialState<{
|
||||
_version: 2;
|
||||
pendingControlImages: string[];
|
||||
}>({
|
||||
_version: 2,
|
||||
pendingControlImages: [],
|
||||
});
|
||||
|
||||
export const selectAllControlNets = (controlAdapters: ControlAdaptersState) =>
|
||||
selectControlAdapterAll(controlAdapters).filter(isControlNet);
|
||||
|
||||
export const selectValidControlNets = (controlAdapters: ControlAdaptersState) =>
|
||||
selectControlAdapterAll(controlAdapters)
|
||||
.filter(isControlNet)
|
||||
.filter(
|
||||
(ca) =>
|
||||
ca.isEnabled &&
|
||||
ca.model &&
|
||||
(Boolean(ca.processedControlImage) || (ca.processorType === 'none' && Boolean(ca.controlImage)))
|
||||
);
|
||||
|
||||
export const selectAllIPAdapters = (controlAdapters: ControlAdaptersState) =>
|
||||
selectControlAdapterAll(controlAdapters).filter(isIPAdapter);
|
||||
|
||||
export const selectValidIPAdapters = (controlAdapters: ControlAdaptersState) =>
|
||||
selectControlAdapterAll(controlAdapters)
|
||||
.filter(isIPAdapter)
|
||||
.filter((ca) => ca.isEnabled && ca.model && Boolean(ca.controlImage));
|
||||
|
||||
export const selectAllT2IAdapters = (controlAdapters: ControlAdaptersState) =>
|
||||
selectControlAdapterAll(controlAdapters).filter(isT2IAdapter);
|
||||
|
||||
export const selectValidT2IAdapters = (controlAdapters: ControlAdaptersState) =>
|
||||
selectControlAdapterAll(controlAdapters)
|
||||
.filter(isT2IAdapter)
|
||||
.filter(
|
||||
(ca) =>
|
||||
ca.isEnabled &&
|
||||
ca.model &&
|
||||
(Boolean(ca.processedControlImage) || (ca.processorType === 'none' && Boolean(ca.controlImage)))
|
||||
);
|
||||
|
||||
export const controlAdaptersSlice = createSlice({
|
||||
name: 'controlAdapters',
|
||||
initialState: initialControlAdaptersState,
|
||||
reducers: {
|
||||
controlAdapterAdded: {
|
||||
reducer: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
id: string;
|
||||
type: ControlAdapterType;
|
||||
overrides?: Partial<ControlAdapterConfig>;
|
||||
}>
|
||||
) => {
|
||||
const { id, type, overrides } = action.payload;
|
||||
caAdapter.addOne(state, buildControlAdapter(id, type, overrides));
|
||||
},
|
||||
prepare: ({ type, overrides }: { type: ControlAdapterType; overrides?: Partial<ControlAdapterConfig> }) => {
|
||||
return { payload: { id: uuidv4(), type, overrides } };
|
||||
},
|
||||
},
|
||||
controlAdapterRecalled: (state, action: PayloadAction<ControlAdapterConfig>) => {
|
||||
caAdapter.addOne(state, action.payload);
|
||||
},
|
||||
controlAdapterDuplicated: {
|
||||
reducer: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
id: string;
|
||||
newId: string;
|
||||
}>
|
||||
) => {
|
||||
const { id, newId } = action.payload;
|
||||
const controlAdapter = selectControlAdapterById(state, id);
|
||||
if (!controlAdapter) {
|
||||
return;
|
||||
}
|
||||
const newControlAdapter = merge(deepClone(controlAdapter), {
|
||||
id: newId,
|
||||
isEnabled: true,
|
||||
});
|
||||
caAdapter.addOne(state, newControlAdapter);
|
||||
},
|
||||
prepare: (id: string) => {
|
||||
return { payload: { id, newId: uuidv4() } };
|
||||
},
|
||||
},
|
||||
controlAdapterRemoved: (state, action: PayloadAction<{ id: string }>) => {
|
||||
caAdapter.removeOne(state, action.payload.id);
|
||||
},
|
||||
controlAdapterIsEnabledChanged: (state, action: PayloadAction<{ id: string; isEnabled: boolean }>) => {
|
||||
const { id, isEnabled } = action.payload;
|
||||
caAdapter.updateOne(state, { id, changes: { isEnabled } });
|
||||
},
|
||||
controlAdapterImageChanged: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
id: string;
|
||||
controlImage: string | null;
|
||||
}>
|
||||
) => {
|
||||
const { id, controlImage } = action.payload;
|
||||
const ca = selectControlAdapterById(state, id);
|
||||
if (!ca) {
|
||||
return;
|
||||
}
|
||||
|
||||
caAdapter.updateOne(state, {
|
||||
id,
|
||||
changes: { controlImage, processedControlImage: null },
|
||||
});
|
||||
|
||||
if (controlImage !== null && isControlNetOrT2IAdapter(ca) && ca.processorType !== 'none') {
|
||||
state.pendingControlImages.push(id);
|
||||
}
|
||||
},
|
||||
controlAdapterProcessedImageChanged: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
id: string;
|
||||
processedControlImage: string | null;
|
||||
}>
|
||||
) => {
|
||||
const { id, processedControlImage } = action.payload;
|
||||
const cn = selectControlAdapterById(state, id);
|
||||
if (!cn) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isControlNetOrT2IAdapter(cn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
caAdapter.updateOne(state, {
|
||||
id,
|
||||
changes: {
|
||||
processedControlImage,
|
||||
},
|
||||
});
|
||||
|
||||
state.pendingControlImages = state.pendingControlImages.filter((pendingId) => pendingId !== id);
|
||||
},
|
||||
controlAdapterModelCleared: (state, action: PayloadAction<{ id: string }>) => {
|
||||
caAdapter.updateOne(state, {
|
||||
id: action.payload.id,
|
||||
changes: { model: null },
|
||||
});
|
||||
},
|
||||
controlAdapterModelChanged: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
id: string;
|
||||
modelConfig: ControlNetModelConfig | T2IAdapterModelConfig | IPAdapterModelConfig;
|
||||
}>
|
||||
) => {
|
||||
const { id, modelConfig } = action.payload;
|
||||
const cn = selectControlAdapterById(state, id);
|
||||
if (!cn) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = zModelIdentifierField.parse(modelConfig);
|
||||
|
||||
if (!isControlNetOrT2IAdapter(cn)) {
|
||||
caAdapter.updateOne(state, { id, changes: { model } });
|
||||
return;
|
||||
}
|
||||
|
||||
const update: Update<ControlNetConfig | T2IAdapterConfig, string> = {
|
||||
id,
|
||||
changes: { model, shouldAutoConfig: true },
|
||||
};
|
||||
|
||||
update.changes.processedControlImage = null;
|
||||
|
||||
if (modelConfig.type === 'ip_adapter') {
|
||||
// should never happen...
|
||||
return;
|
||||
}
|
||||
|
||||
const processor = buildControlAdapterProcessor(modelConfig);
|
||||
update.changes.processorType = processor.processorType;
|
||||
update.changes.processorNode = processor.processorNode;
|
||||
|
||||
caAdapter.updateOne(state, update);
|
||||
},
|
||||
controlAdapterWeightChanged: (state, action: PayloadAction<{ id: string; weight: number }>) => {
|
||||
const { id, weight } = action.payload;
|
||||
caAdapter.updateOne(state, { id, changes: { weight } });
|
||||
},
|
||||
controlAdapterBeginStepPctChanged: (state, action: PayloadAction<{ id: string; beginStepPct: number }>) => {
|
||||
const { id, beginStepPct } = action.payload;
|
||||
caAdapter.updateOne(state, { id, changes: { beginStepPct } });
|
||||
},
|
||||
controlAdapterEndStepPctChanged: (state, action: PayloadAction<{ id: string; endStepPct: number }>) => {
|
||||
const { id, endStepPct } = action.payload;
|
||||
caAdapter.updateOne(state, { id, changes: { endStepPct } });
|
||||
},
|
||||
controlAdapterControlModeChanged: (state, action: PayloadAction<{ id: string; controlMode: ControlMode }>) => {
|
||||
const { id, controlMode } = action.payload;
|
||||
const cn = selectControlAdapterById(state, id);
|
||||
if (!cn || !isControlNet(cn)) {
|
||||
return;
|
||||
}
|
||||
caAdapter.updateOne(state, { id, changes: { controlMode } });
|
||||
},
|
||||
controlAdapterIPMethodChanged: (state, action: PayloadAction<{ id: string; method: IPMethod }>) => {
|
||||
const { id, method } = action.payload;
|
||||
caAdapter.updateOne(state, { id, changes: { method } });
|
||||
},
|
||||
controlAdapterCLIPVisionModelChanged: (
|
||||
state,
|
||||
action: PayloadAction<{ id: string; clipVisionModel: CLIPVisionModel }>
|
||||
) => {
|
||||
const { id, clipVisionModel } = action.payload;
|
||||
caAdapter.updateOne(state, { id, changes: { clipVisionModel } });
|
||||
},
|
||||
controlAdapterResizeModeChanged: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
id: string;
|
||||
resizeMode: ResizeMode;
|
||||
}>
|
||||
) => {
|
||||
const { id, resizeMode } = action.payload;
|
||||
const cn = selectControlAdapterById(state, id);
|
||||
if (!cn || !isControlNetOrT2IAdapter(cn)) {
|
||||
return;
|
||||
}
|
||||
caAdapter.updateOne(state, { id, changes: { resizeMode } });
|
||||
},
|
||||
controlAdapterProcessorParamsChanged: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
id: string;
|
||||
params: Partial<RequiredControlAdapterProcessorNode>;
|
||||
}>
|
||||
) => {
|
||||
const { id, params } = action.payload;
|
||||
const cn = selectControlAdapterById(state, id);
|
||||
if (!cn || !isControlNetOrT2IAdapter(cn) || !cn.processorNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const processorNode = merge(deepClone(cn.processorNode), params);
|
||||
|
||||
caAdapter.updateOne(state, {
|
||||
id,
|
||||
changes: {
|
||||
shouldAutoConfig: false,
|
||||
processorNode,
|
||||
},
|
||||
});
|
||||
},
|
||||
controlAdapterProcessortTypeChanged: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
id: string;
|
||||
processorType: ControlAdapterProcessorType;
|
||||
}>
|
||||
) => {
|
||||
const { id, processorType } = action.payload;
|
||||
const cn = selectControlAdapterById(state, id);
|
||||
if (!cn || !isControlNetOrT2IAdapter(cn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const processorNode = deepClone(
|
||||
CONTROLNET_PROCESSORS[processorType].buildDefaults(cn.model?.base)
|
||||
) as RequiredControlAdapterProcessorNode;
|
||||
|
||||
caAdapter.updateOne(state, {
|
||||
id,
|
||||
changes: {
|
||||
processorType,
|
||||
processedControlImage: null,
|
||||
processorNode,
|
||||
shouldAutoConfig: false,
|
||||
},
|
||||
});
|
||||
},
|
||||
controlAdapterAutoConfigToggled: (
|
||||
state,
|
||||
action: PayloadAction<{
|
||||
id: string;
|
||||
modelConfig?: ControlNetModelConfig | T2IAdapterModelConfig | IPAdapterModelConfig;
|
||||
}>
|
||||
) => {
|
||||
const { id, modelConfig } = action.payload;
|
||||
const cn = selectControlAdapterById(state, id);
|
||||
if (!cn || !isControlNetOrT2IAdapter(cn) || modelConfig?.type === 'ip_adapter') {
|
||||
return;
|
||||
}
|
||||
const update: Update<ControlNetConfig | T2IAdapterConfig, string> = {
|
||||
id,
|
||||
changes: { shouldAutoConfig: !cn.shouldAutoConfig },
|
||||
};
|
||||
|
||||
if (update.changes.shouldAutoConfig && modelConfig) {
|
||||
const processor = buildControlAdapterProcessor(modelConfig);
|
||||
update.changes.processorType = processor.processorType;
|
||||
update.changes.processorNode = processor.processorNode;
|
||||
}
|
||||
|
||||
caAdapter.updateOne(state, update);
|
||||
},
|
||||
controlAdaptersReset: () => {
|
||||
return deepClone(initialControlAdaptersState);
|
||||
},
|
||||
pendingControlImagesCleared: (state) => {
|
||||
state.pendingControlImages = [];
|
||||
},
|
||||
ipAdaptersReset: (state) => {
|
||||
selectAllIPAdapters(state).forEach((ca) => {
|
||||
caAdapter.removeOne(state, ca.id);
|
||||
});
|
||||
},
|
||||
controlNetsReset: (state) => {
|
||||
selectAllControlNets(state).forEach((ca) => {
|
||||
caAdapter.removeOne(state, ca.id);
|
||||
});
|
||||
},
|
||||
t2iAdaptersReset: (state) => {
|
||||
selectAllT2IAdapters(state).forEach((ca) => {
|
||||
caAdapter.removeOne(state, ca.id);
|
||||
});
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder.addCase(controlAdapterImageProcessed, (state, action) => {
|
||||
const cn = selectControlAdapterById(state, action.payload.id);
|
||||
if (!cn) {
|
||||
return;
|
||||
}
|
||||
if (cn.controlImage !== null) {
|
||||
state.pendingControlImages = uniq(state.pendingControlImages.concat(action.payload.id));
|
||||
}
|
||||
});
|
||||
|
||||
builder.addCase(socketInvocationError, (state) => {
|
||||
state.pendingControlImages = [];
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
controlAdapterAdded,
|
||||
controlAdapterRecalled,
|
||||
controlAdapterDuplicated,
|
||||
controlAdapterRemoved,
|
||||
controlAdapterImageChanged,
|
||||
controlAdapterProcessedImageChanged,
|
||||
controlAdapterIsEnabledChanged,
|
||||
controlAdapterModelChanged,
|
||||
controlAdapterCLIPVisionModelChanged,
|
||||
controlAdapterIPMethodChanged,
|
||||
controlAdapterWeightChanged,
|
||||
controlAdapterBeginStepPctChanged,
|
||||
controlAdapterEndStepPctChanged,
|
||||
controlAdapterControlModeChanged,
|
||||
controlAdapterResizeModeChanged,
|
||||
controlAdapterProcessorParamsChanged,
|
||||
controlAdapterProcessortTypeChanged,
|
||||
controlAdaptersReset,
|
||||
controlAdapterAutoConfigToggled,
|
||||
pendingControlImagesCleared,
|
||||
controlAdapterModelCleared,
|
||||
ipAdaptersReset,
|
||||
controlNetsReset,
|
||||
t2iAdaptersReset,
|
||||
} = controlAdaptersSlice.actions;
|
||||
|
||||
export const selectControlAdaptersSlice = (state: RootState) => state.controlAdapters;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateControlAdaptersState = (state: any): any => {
|
||||
if (!('_version' in state)) {
|
||||
state._version = 1;
|
||||
}
|
||||
if (state._version === 1) {
|
||||
state = deepClone(initialControlAdaptersState);
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const controlAdaptersPersistConfig: PersistConfig<ControlAdaptersState> = {
|
||||
name: controlAdaptersSlice.name,
|
||||
initialState: initialControlAdaptersState,
|
||||
migrate: migrateControlAdaptersState,
|
||||
persistDenylist: ['pendingControlImages'],
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
import type { ControlAdapterProcessorType, zControlAdapterProcessorType } from 'features/controlAdapters/store/types';
|
||||
import type { Equals } from 'tsafe';
|
||||
import { assert } from 'tsafe';
|
||||
import { describe, test } from 'vitest';
|
||||
import type { z } from 'zod';
|
||||
|
||||
describe('Control Adapter Types', () => {
|
||||
test('ControlAdapterProcessorType', () =>
|
||||
assert<Equals<ControlAdapterProcessorType, z.infer<typeof zControlAdapterProcessorType>>>());
|
||||
});
|
@ -1,274 +0,0 @@
|
||||
import type { EntityState } from '@reduxjs/toolkit';
|
||||
import type {
|
||||
ParameterControlNetModel,
|
||||
ParameterIPAdapterModel,
|
||||
ParameterT2IAdapterModel,
|
||||
} from 'features/parameters/types/parameterSchemas';
|
||||
import type { components } from 'services/api/schema';
|
||||
import type { Invocation } from 'services/api/types';
|
||||
import type { O } from 'ts-toolbelt';
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Any ControlNet processor node
|
||||
*/
|
||||
export type ControlAdapterProcessorNode =
|
||||
| Invocation<'canny_image_processor'>
|
||||
| Invocation<'color_map_image_processor'>
|
||||
| Invocation<'content_shuffle_image_processor'>
|
||||
| Invocation<'depth_anything_image_processor'>
|
||||
| Invocation<'hed_image_processor'>
|
||||
| Invocation<'lineart_anime_image_processor'>
|
||||
| Invocation<'lineart_image_processor'>
|
||||
| Invocation<'mediapipe_face_processor'>
|
||||
| Invocation<'midas_depth_image_processor'>
|
||||
| Invocation<'mlsd_image_processor'>
|
||||
| Invocation<'normalbae_image_processor'>
|
||||
| Invocation<'dw_openpose_image_processor'>
|
||||
| Invocation<'pidi_image_processor'>
|
||||
| Invocation<'zoe_depth_image_processor'>;
|
||||
|
||||
/**
|
||||
* Any ControlNet processor type
|
||||
*/
|
||||
export type ControlAdapterProcessorType = NonNullable<ControlAdapterProcessorNode['type'] | 'none'>;
|
||||
export const zControlAdapterProcessorType = z.enum([
|
||||
'canny_image_processor',
|
||||
'color_map_image_processor',
|
||||
'content_shuffle_image_processor',
|
||||
'depth_anything_image_processor',
|
||||
'hed_image_processor',
|
||||
'lineart_anime_image_processor',
|
||||
'lineart_image_processor',
|
||||
'mediapipe_face_processor',
|
||||
'midas_depth_image_processor',
|
||||
'mlsd_image_processor',
|
||||
'normalbae_image_processor',
|
||||
'dw_openpose_image_processor',
|
||||
'pidi_image_processor',
|
||||
'zoe_depth_image_processor',
|
||||
'none',
|
||||
]);
|
||||
export const isControlAdapterProcessorType = (v: unknown): v is ControlAdapterProcessorType =>
|
||||
zControlAdapterProcessorType.safeParse(v).success;
|
||||
|
||||
/**
|
||||
* The Canny processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredCannyImageProcessorInvocation = O.Required<
|
||||
Invocation<'canny_image_processor'>,
|
||||
'type' | 'low_threshold' | 'high_threshold' | 'image_resolution' | 'detect_resolution'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The Color Map processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredColorMapImageProcessorInvocation = O.Required<
|
||||
Invocation<'color_map_image_processor'>,
|
||||
'type' | 'color_map_tile_size'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The ContentShuffle processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredContentShuffleImageProcessorInvocation = O.Required<
|
||||
Invocation<'content_shuffle_image_processor'>,
|
||||
'type' | 'detect_resolution' | 'image_resolution' | 'w' | 'h' | 'f'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The DepthAnything processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredDepthAnythingImageProcessorInvocation = O.Required<
|
||||
Invocation<'depth_anything_image_processor'>,
|
||||
'type' | 'model_size' | 'resolution' | 'offload'
|
||||
>;
|
||||
|
||||
const zDepthAnythingModelSize = z.enum(['large', 'base', 'small', 'small_v2']);
|
||||
export type DepthAnythingModelSize = z.infer<typeof zDepthAnythingModelSize>;
|
||||
export const isDepthAnythingModelSize = (v: unknown): v is DepthAnythingModelSize =>
|
||||
zDepthAnythingModelSize.safeParse(v).success;
|
||||
|
||||
/**
|
||||
* The HED processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredHedImageProcessorInvocation = O.Required<
|
||||
Invocation<'hed_image_processor'>,
|
||||
'type' | 'detect_resolution' | 'image_resolution' | 'scribble'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The Lineart Anime processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredLineartAnimeImageProcessorInvocation = O.Required<
|
||||
Invocation<'lineart_anime_image_processor'>,
|
||||
'type' | 'detect_resolution' | 'image_resolution'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The Lineart processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredLineartImageProcessorInvocation = O.Required<
|
||||
Invocation<'lineart_image_processor'>,
|
||||
'type' | 'detect_resolution' | 'image_resolution' | 'coarse'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The MediapipeFace processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredMediapipeFaceProcessorInvocation = O.Required<
|
||||
Invocation<'mediapipe_face_processor'>,
|
||||
'type' | 'max_faces' | 'min_confidence' | 'image_resolution' | 'detect_resolution'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The MidasDepth processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredMidasDepthImageProcessorInvocation = O.Required<
|
||||
Invocation<'midas_depth_image_processor'>,
|
||||
'type' | 'a_mult' | 'bg_th' | 'image_resolution' | 'detect_resolution'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The MLSD processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredMlsdImageProcessorInvocation = O.Required<
|
||||
Invocation<'mlsd_image_processor'>,
|
||||
'type' | 'detect_resolution' | 'image_resolution' | 'thr_v' | 'thr_d'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The NormalBae processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredNormalbaeImageProcessorInvocation = O.Required<
|
||||
Invocation<'normalbae_image_processor'>,
|
||||
'type' | 'detect_resolution' | 'image_resolution'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The DW Openpose processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredDWOpenposeImageProcessorInvocation = O.Required<
|
||||
Invocation<'dw_openpose_image_processor'>,
|
||||
'type' | 'image_resolution' | 'draw_body' | 'draw_face' | 'draw_hands'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The Pidi processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredPidiImageProcessorInvocation = O.Required<
|
||||
Invocation<'pidi_image_processor'>,
|
||||
'type' | 'detect_resolution' | 'image_resolution' | 'safe' | 'scribble'
|
||||
>;
|
||||
|
||||
/**
|
||||
* The ZoeDepth processor node, with parameters flagged as required
|
||||
*/
|
||||
export type RequiredZoeDepthImageProcessorInvocation = O.Required<Invocation<'zoe_depth_image_processor'>, 'type'>;
|
||||
|
||||
/**
|
||||
* Any ControlNet Processor node, with its parameters flagged as required
|
||||
*/
|
||||
export type RequiredControlAdapterProcessorNode =
|
||||
| O.Required<
|
||||
| RequiredCannyImageProcessorInvocation
|
||||
| RequiredColorMapImageProcessorInvocation
|
||||
| RequiredContentShuffleImageProcessorInvocation
|
||||
| RequiredDepthAnythingImageProcessorInvocation
|
||||
| RequiredHedImageProcessorInvocation
|
||||
| RequiredLineartAnimeImageProcessorInvocation
|
||||
| RequiredLineartImageProcessorInvocation
|
||||
| RequiredMediapipeFaceProcessorInvocation
|
||||
| RequiredMidasDepthImageProcessorInvocation
|
||||
| RequiredMlsdImageProcessorInvocation
|
||||
| RequiredNormalbaeImageProcessorInvocation
|
||||
| RequiredDWOpenposeImageProcessorInvocation
|
||||
| RequiredPidiImageProcessorInvocation
|
||||
| RequiredZoeDepthImageProcessorInvocation,
|
||||
'id'
|
||||
>
|
||||
| { type: 'none' };
|
||||
|
||||
export type ControlMode = NonNullable<components['schemas']['ControlNetInvocation']['control_mode']>;
|
||||
|
||||
const zResizeMode = z.enum(['just_resize', 'crop_resize', 'fill_resize', 'just_resize_simple']);
|
||||
export type ResizeMode = z.infer<typeof zResizeMode>;
|
||||
export const isResizeMode = (v: unknown): v is ResizeMode => zResizeMode.safeParse(v).success;
|
||||
|
||||
const zIPMethod = z.enum(['full', 'style', 'composition']);
|
||||
export type IPMethod = z.infer<typeof zIPMethod>;
|
||||
export const isIPMethod = (v: unknown): v is IPMethod => zIPMethod.safeParse(v).success;
|
||||
|
||||
export type ControlNetConfig = {
|
||||
type: 'controlnet';
|
||||
id: string;
|
||||
isEnabled: boolean;
|
||||
model: ParameterControlNetModel | null;
|
||||
weight: number;
|
||||
beginStepPct: number;
|
||||
endStepPct: number;
|
||||
controlMode: ControlMode;
|
||||
resizeMode: ResizeMode;
|
||||
controlImage: string | null;
|
||||
processedControlImage: string | null;
|
||||
processorType: ControlAdapterProcessorType;
|
||||
processorNode: RequiredControlAdapterProcessorNode;
|
||||
shouldAutoConfig: boolean;
|
||||
};
|
||||
|
||||
export type T2IAdapterConfig = {
|
||||
type: 't2i_adapter';
|
||||
id: string;
|
||||
isEnabled: boolean;
|
||||
model: ParameterT2IAdapterModel | null;
|
||||
weight: number;
|
||||
beginStepPct: number;
|
||||
endStepPct: number;
|
||||
resizeMode: ResizeMode;
|
||||
controlImage: string | null;
|
||||
processedControlImage: string | null;
|
||||
processorType: ControlAdapterProcessorType;
|
||||
processorNode: RequiredControlAdapterProcessorNode;
|
||||
shouldAutoConfig: boolean;
|
||||
};
|
||||
|
||||
export type CLIPVisionModel = 'ViT-H' | 'ViT-G';
|
||||
|
||||
export type IPAdapterConfig = {
|
||||
type: 'ip_adapter';
|
||||
id: string;
|
||||
isEnabled: boolean;
|
||||
controlImage: string | null;
|
||||
model: ParameterIPAdapterModel | null;
|
||||
clipVisionModel: CLIPVisionModel;
|
||||
weight: number;
|
||||
method: IPMethod;
|
||||
beginStepPct: number;
|
||||
endStepPct: number;
|
||||
};
|
||||
|
||||
export type ControlAdapterConfig = ControlNetConfig | IPAdapterConfig | T2IAdapterConfig;
|
||||
|
||||
export type ControlAdapterType = ControlAdapterConfig['type'];
|
||||
|
||||
export type ControlAdaptersState = EntityState<ControlAdapterConfig, string> & {
|
||||
pendingControlImages: string[];
|
||||
};
|
||||
|
||||
export const isControlNet = (controlAdapter: ControlAdapterConfig): controlAdapter is ControlNetConfig => {
|
||||
return controlAdapter.type === 'controlnet';
|
||||
};
|
||||
|
||||
export const isIPAdapter = (controlAdapter: ControlAdapterConfig): controlAdapter is IPAdapterConfig => {
|
||||
return controlAdapter.type === 'ip_adapter';
|
||||
};
|
||||
|
||||
export const isT2IAdapter = (controlAdapter: ControlAdapterConfig): controlAdapter is T2IAdapterConfig => {
|
||||
return controlAdapter.type === 't2i_adapter';
|
||||
};
|
||||
|
||||
export const isControlNetOrT2IAdapter = (
|
||||
controlAdapter: ControlAdapterConfig
|
||||
): controlAdapter is ControlNetConfig | T2IAdapterConfig => {
|
||||
return isControlNet(controlAdapter) || isT2IAdapter(controlAdapter);
|
||||
};
|
@ -1,71 +0,0 @@
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
|
||||
import type {
|
||||
ControlAdapterConfig,
|
||||
ControlAdapterType,
|
||||
ControlNetConfig,
|
||||
IPAdapterConfig,
|
||||
RequiredCannyImageProcessorInvocation,
|
||||
T2IAdapterConfig,
|
||||
} from 'features/controlAdapters/store/types';
|
||||
import { merge } from 'lodash-es';
|
||||
|
||||
export const initialControlNet: Omit<ControlNetConfig, 'id'> = {
|
||||
type: 'controlnet',
|
||||
isEnabled: true,
|
||||
model: null,
|
||||
weight: 1,
|
||||
beginStepPct: 0,
|
||||
endStepPct: 1,
|
||||
controlMode: 'balanced',
|
||||
resizeMode: 'just_resize',
|
||||
controlImage: null,
|
||||
processedControlImage: null,
|
||||
processorType: 'canny_image_processor',
|
||||
processorNode: CONTROLNET_PROCESSORS.canny_image_processor.buildDefaults() as RequiredCannyImageProcessorInvocation,
|
||||
shouldAutoConfig: true,
|
||||
};
|
||||
|
||||
export const initialT2IAdapter: Omit<T2IAdapterConfig, 'id'> = {
|
||||
type: 't2i_adapter',
|
||||
isEnabled: true,
|
||||
model: null,
|
||||
weight: 1,
|
||||
beginStepPct: 0,
|
||||
endStepPct: 1,
|
||||
resizeMode: 'just_resize',
|
||||
controlImage: null,
|
||||
processedControlImage: null,
|
||||
processorType: 'canny_image_processor',
|
||||
processorNode: CONTROLNET_PROCESSORS.canny_image_processor.buildDefaults() as RequiredCannyImageProcessorInvocation,
|
||||
shouldAutoConfig: true,
|
||||
};
|
||||
|
||||
export const initialIPAdapter: Omit<IPAdapterConfig, 'id'> = {
|
||||
type: 'ip_adapter',
|
||||
isEnabled: true,
|
||||
controlImage: null,
|
||||
model: null,
|
||||
method: 'full',
|
||||
clipVisionModel: 'ViT-H',
|
||||
weight: 1,
|
||||
beginStepPct: 0,
|
||||
endStepPct: 1,
|
||||
};
|
||||
|
||||
export const buildControlAdapter = (
|
||||
id: string,
|
||||
type: ControlAdapterType,
|
||||
overrides: Partial<ControlAdapterConfig> = {}
|
||||
): ControlAdapterConfig => {
|
||||
switch (type) {
|
||||
case 'controlnet':
|
||||
return merge(deepClone(initialControlNet), { id, ...overrides });
|
||||
case 't2i_adapter':
|
||||
return merge(deepClone(initialT2IAdapter), { id, ...overrides });
|
||||
case 'ip_adapter':
|
||||
return merge(deepClone(initialIPAdapter), { id, ...overrides });
|
||||
default:
|
||||
throw new Error(`Unknown control adapter type: ${type}`);
|
||||
}
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
import { CONTROLNET_PROCESSORS } from 'features/controlAdapters/store/constants';
|
||||
import { isControlAdapterProcessorType } from 'features/controlAdapters/store/types';
|
||||
import type { ControlNetModelConfig, T2IAdapterModelConfig } from 'services/api/types';
|
||||
|
||||
export const buildControlAdapterProcessor = (modelConfig: ControlNetModelConfig | T2IAdapterModelConfig) => {
|
||||
const defaultPreprocessor = modelConfig.default_settings?.preprocessor;
|
||||
const processorType = isControlAdapterProcessorType(defaultPreprocessor) ? defaultPreprocessor : 'none';
|
||||
const processorNode = CONTROLNET_PROCESSORS[processorType].buildDefaults(modelConfig.base);
|
||||
|
||||
return { processorType, processorNode };
|
||||
};
|
Loading…
Reference in New Issue
Block a user