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 type { AppDispatch } from 'app/store/store';
|
||||||
import { parseify } from 'common/util/serialize';
|
import { parseify } from 'common/util/serialize';
|
||||||
import {
|
import {
|
||||||
controlAdapterImageChanged,
|
caImageChanged,
|
||||||
controlAdapterModelChanged,
|
caModelChanged,
|
||||||
controlAdapterProcessedImageChanged,
|
caProcessedImageChanged,
|
||||||
controlAdapterProcessorConfigChanged,
|
caProcessorConfigChanged,
|
||||||
controlAdapterProcessorPendingBatchIdChanged,
|
caProcessorPendingBatchIdChanged,
|
||||||
controlAdapterRecalled,
|
caRecalled,
|
||||||
} from 'features/controlLayers/store/canvasV2Slice';
|
} from 'features/controlLayers/store/canvasV2Slice';
|
||||||
import { isControlAdapterLayer } from 'features/controlLayers/store/types';
|
import { selectCA } from 'features/controlLayers/store/controlAdaptersReducers';
|
||||||
import { CA_PROCESSOR_DATA } from 'features/controlLayers/util/controlAdapters';
|
import { CA_PROCESSOR_DATA } from 'features/controlLayers/store/types';
|
||||||
import { toast } from 'features/toast/toast';
|
import { toast } from 'features/toast/toast';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
@ -22,13 +22,7 @@ import type { BatchConfig } from 'services/api/types';
|
|||||||
import { socketInvocationComplete } from 'services/events/actions';
|
import { socketInvocationComplete } from 'services/events/actions';
|
||||||
import { assert } from 'tsafe';
|
import { assert } from 'tsafe';
|
||||||
|
|
||||||
const matcher = isAnyOf(
|
const matcher = isAnyOf(caImageChanged, caProcessedImageChanged, caProcessorConfigChanged, caModelChanged, caRecalled);
|
||||||
controlAdapterImageChanged,
|
|
||||||
controlAdapterProcessedImageChanged,
|
|
||||||
controlAdapterProcessorConfigChanged,
|
|
||||||
controlAdapterModelChanged,
|
|
||||||
controlAdapterRecalled
|
|
||||||
);
|
|
||||||
|
|
||||||
const DEBOUNCE_MS = 300;
|
const DEBOUNCE_MS = 300;
|
||||||
const log = logger('session');
|
const log = logger('session');
|
||||||
@ -36,7 +30,7 @@ const log = logger('session');
|
|||||||
/**
|
/**
|
||||||
* Simple helper to cancel a batch and reset the pending batch ID
|
* 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] }));
|
const req = dispatch(queueApi.endpoints.cancelByBatchIds.initiate({ batch_ids: [batchId] }));
|
||||||
log.trace({ batchId }, 'Cancelling existing preprocessor batch');
|
log.trace({ batchId }, 'Cancelling existing preprocessor batch');
|
||||||
try {
|
try {
|
||||||
@ -46,7 +40,7 @@ const cancelProcessorBatch = async (dispatch: AppDispatch, layerId: string, batc
|
|||||||
} finally {
|
} finally {
|
||||||
req.reset();
|
req.reset();
|
||||||
// Always reset the pending batch ID - the cancel req could fail if the batch doesn't exist
|
// 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({
|
startAppListening({
|
||||||
matcher,
|
matcher,
|
||||||
effect: async (action, { dispatch, getState, getOriginalState, cancelActiveListeners, delay, take, signal }) => {
|
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 state = getState();
|
||||||
const originalState = getOriginalState();
|
const originalState = getOriginalState();
|
||||||
|
|
||||||
@ -65,22 +59,20 @@ export const addControlAdapterPreprocessor = (startAppListening: AppStartListeni
|
|||||||
// Delay before starting actual work
|
// Delay before starting actual work
|
||||||
await delay(DEBOUNCE_MS);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should only process if the processor settings or image have changed
|
// We should only process if the processor settings or image have changed
|
||||||
const originalLayer = originalState.canvasV2.layers
|
const originalCA = selectCA(originalState.canvasV2, id);
|
||||||
.filter(isControlAdapterLayer)
|
const originalImage = originalCA?.image;
|
||||||
.find((l) => l.id === layerId);
|
const originalConfig = originalCA?.processorConfig;
|
||||||
const originalImage = originalLayer?.controlAdapter.image;
|
|
||||||
const originalConfig = originalLayer?.controlAdapter.processorConfig;
|
|
||||||
|
|
||||||
const image = layer.controlAdapter.image;
|
const image = ca.image;
|
||||||
const processedImage = layer.controlAdapter.processedImage;
|
const processedImage = ca.processedImage;
|
||||||
const config = layer.controlAdapter.processorConfig;
|
const config = ca.processorConfig;
|
||||||
|
|
||||||
if (isEqual(config, originalConfig) && isEqual(image, originalImage) && processedImage) {
|
if (isEqual(config, originalConfig) && isEqual(image, originalImage) && processedImage) {
|
||||||
// Neither config nor image have changed, we can bail
|
// 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 image, we have nothing to process
|
||||||
// - If we have no processor config, we have nothing to process
|
// - If we have no processor config, we have nothing to process
|
||||||
// Clear the processed image and bail
|
// Clear the processed image and bail
|
||||||
dispatch(controlAdapterProcessedImageChanged({ layerId, imageDTO: null }));
|
dispatch(caProcessedImageChanged({ id, imageDTO: null }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, the user has stopped fiddling with the processor settings and there is a processor selected.
|
// 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 there is a pending processor batch, cancel it.
|
||||||
if (layer.controlAdapter.processorPendingBatchId) {
|
if (ca.processorPendingBatchId) {
|
||||||
cancelProcessorBatch(dispatch, layerId, layer.controlAdapter.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
|
// 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();
|
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
|
// 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');
|
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'));
|
log.debug({ enqueueResult: parseify(enqueueResult) }, t('queue.graphQueued'));
|
||||||
|
|
||||||
// Wait for the processor node to complete
|
// 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");
|
assert(imageDTO, "Failed to fetch processor output's image DTO");
|
||||||
|
|
||||||
// Whew! We made it. Update the layer with the processed image
|
// Whew! We made it. Update the layer with the processed image
|
||||||
log.debug({ layerId, imageDTO }, 'ControlNet image processed');
|
log.debug({ id, imageDTO }, 'ControlNet image processed');
|
||||||
dispatch(controlAdapterProcessedImageChanged({ layerId, imageDTO }));
|
dispatch(caProcessedImageChanged({ id, imageDTO }));
|
||||||
dispatch(controlAdapterProcessorPendingBatchIdChanged({ layerId, batchId: null }));
|
dispatch(caProcessorPendingBatchIdChanged({ id, batchId: null }));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (signal.aborted) {
|
if (signal.aborted) {
|
||||||
// The listener was canceled - we need to cancel the pending processor batch, if there is one (could have changed by now).
|
// The listener was canceled - we need to cancel the pending processor batch, if there is one (could have changed by now).
|
||||||
const pendingBatchId = getState()
|
const pendingBatchId = selectCA(getState().canvasV2, id)?.processorPendingBatchId;
|
||||||
.canvasV2.layers.filter(isControlAdapterLayer)
|
|
||||||
.find((l) => l.id === layerId)?.controlAdapter.processorPendingBatchId;
|
|
||||||
if (pendingBatchId) {
|
if (pendingBatchId) {
|
||||||
cancelProcessorBatch(dispatch, layerId, pendingBatchId);
|
cancelProcessorBatch(dispatch, id, pendingBatchId);
|
||||||
}
|
}
|
||||||
log.trace('Control Adapter preprocessor cancelled');
|
log.trace('Control Adapter preprocessor cancelled');
|
||||||
} else {
|
} else {
|
||||||
@ -174,7 +164,7 @@ export const addControlAdapterPreprocessor = (startAppListening: AppStartListeni
|
|||||||
if (error instanceof Object) {
|
if (error instanceof Object) {
|
||||||
if ('data' in error && 'status' in error) {
|
if ('data' in error && 'status' in error) {
|
||||||
if (error.status === 403) {
|
if (error.status === 403) {
|
||||||
dispatch(controlAdapterImageChanged({ layerId, imageDTO: null }));
|
dispatch(caImageChanged({ id, imageDTO: null }));
|
||||||
return;
|
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