From 7be5743011b5cd2b2a07cbc2eff97dca9381f204 Mon Sep 17 00:00:00 2001 From: blessedcoolant <54517381+blessedcoolant@users.noreply.github.com> Date: Sun, 17 Sep 2023 11:53:05 +1200 Subject: [PATCH] feat: Add IP Adapter Begin & End Percent to Linear UI --- .../components/ipAdapter/IPAdapterPanel.tsx | 2 + .../ipAdapter/ParamIPAdapterBeginEnd.tsx | 100 ++++++++++++++++++ .../controlNet/store/controlNetSlice.ts | 12 +++ .../addIPAdapterToLinearGraph.ts | 8 +- .../frontend/web/src/services/api/schema.d.ts | 68 ++++++++---- 5 files changed, 165 insertions(+), 25 deletions(-) create mode 100644 invokeai/frontend/web/src/features/controlNet/components/ipAdapter/ParamIPAdapterBeginEnd.tsx diff --git a/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/IPAdapterPanel.tsx b/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/IPAdapterPanel.tsx index 9dbd7e2ffa..b0a1fcc731 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/IPAdapterPanel.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/IPAdapterPanel.tsx @@ -1,5 +1,6 @@ import { Flex } from '@chakra-ui/react'; import { memo } from 'react'; +import ParamIPAdapterBeginEnd from './ParamIPAdapterBeginEnd'; import ParamIPAdapterFeatureToggle from './ParamIPAdapterFeatureToggle'; import ParamIPAdapterImage from './ParamIPAdapterImage'; import ParamIPAdapterModelSelect from './ParamIPAdapterModelSelect'; @@ -26,6 +27,7 @@ const IPAdapterPanel = () => { + ); }; diff --git a/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/ParamIPAdapterBeginEnd.tsx b/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/ParamIPAdapterBeginEnd.tsx new file mode 100644 index 0000000000..5bef23b66c --- /dev/null +++ b/invokeai/frontend/web/src/features/controlNet/components/ipAdapter/ParamIPAdapterBeginEnd.tsx @@ -0,0 +1,100 @@ +import { + FormControl, + FormLabel, + HStack, + RangeSlider, + RangeSliderFilledTrack, + RangeSliderMark, + RangeSliderThumb, + RangeSliderTrack, + Tooltip, +} from '@chakra-ui/react'; +import { RootState } from 'app/store/store'; +import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { + ipAdapterBeginStepPctChanged, + ipAdapterEndStepPctChanged, +} from 'features/controlNet/store/controlNetSlice'; +import { memo, useCallback } from 'react'; +import { useTranslation } from 'react-i18next'; + +const formatPct = (v: number) => `${Math.round(v * 100)}%`; + +const ParamIPAdapterBeginEnd = () => { + const isEnabled = useAppSelector( + (state: RootState) => state.controlNet.isIPAdapterEnabled + ); + const beginStepPct = useAppSelector( + (state: RootState) => state.controlNet.ipAdapterInfo.beginStepPct + ); + const endStepPct = useAppSelector( + (state: RootState) => state.controlNet.ipAdapterInfo.endStepPct + ); + const dispatch = useAppDispatch(); + const { t } = useTranslation(); + + const handleStepPctChanged = useCallback( + (v: number[]) => { + dispatch(ipAdapterBeginStepPctChanged(v[0] as number)); + dispatch(ipAdapterEndStepPctChanged(v[1] as number)); + }, + [dispatch] + ); + + return ( + + {t('controlnet.beginEndStepPercent')} + + + + + + + + + + + + + 0% + + + 50% + + + 100% + + + + + ); +}; + +export default memo(ParamIPAdapterBeginEnd); diff --git a/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts b/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts index df55c44cf3..3fe57f4a84 100644 --- a/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts +++ b/invokeai/frontend/web/src/features/controlNet/store/controlNetSlice.ts @@ -64,6 +64,8 @@ export type IPAdapterConfig = { adapterImage: ImageDTO | null; model: IPAdapterModelParam | null; weight: number; + beginStepPct: number; + endStepPct: number; }; export type ControlNetState = { @@ -78,6 +80,8 @@ export const initialIPAdapterState: IPAdapterConfig = { adapterImage: null, model: null, weight: 1, + beginStepPct: 0, + endStepPct: 1, }; export const initialControlNetState: ControlNetState = { @@ -388,6 +392,12 @@ export const controlNetSlice = createSlice({ ) => { state.ipAdapterInfo.model = action.payload; }, + ipAdapterBeginStepPctChanged: (state, action: PayloadAction) => { + state.ipAdapterInfo.beginStepPct = action.payload; + }, + ipAdapterEndStepPctChanged: (state, action: PayloadAction) => { + state.ipAdapterInfo.endStepPct = action.payload; + }, ipAdapterStateReset: (state) => { state.isIPAdapterEnabled = false; state.ipAdapterInfo = { ...initialIPAdapterState }; @@ -455,6 +465,8 @@ export const { ipAdapterImageChanged, ipAdapterWeightChanged, ipAdapterModelChanged, + ipAdapterBeginStepPctChanged, + ipAdapterEndStepPctChanged, ipAdapterStateReset, } = controlNetSlice.actions; diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts index 95b63e7c3f..da67b1d34d 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/addIPAdapterToLinearGraph.ts @@ -14,16 +14,18 @@ export const addIPAdapterToLinearGraph = ( // | MetadataAccumulatorInvocation // | undefined; - if (isIPAdapterEnabled) { + if (isIPAdapterEnabled && ipAdapterInfo.model) { const ipAdapterNode: IPAdapterInvocation = { id: IP_ADAPTER, type: 'ip_adapter', is_intermediate: true, weight: ipAdapterInfo.weight, ip_adapter_model: { - base_model: 'sd-1', - model_name: 'ip_adapter_plus_sd15', + base_model: ipAdapterInfo.model?.base_model, + model_name: ipAdapterInfo.model?.model_name, }, + begin_step_percent: ipAdapterInfo.beginStepPct, + end_step_percent: ipAdapterInfo.endStepPct, }; if (ipAdapterInfo.adapterImage) { diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 91749c585f..b36f64e90c 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -2564,10 +2564,22 @@ export type components = { image_encoder_model: components["schemas"]["CLIPVisionModelField"]; /** * Weight - * @description The weight of the IP-Adapter. + * @description The weight given to the ControlNet * @default 1 */ - weight?: number; + weight?: number | number[]; + /** + * Begin Step Percent + * @description When the IP-Adapter is first applied (% of total steps) + * @default 0 + */ + begin_step_percent?: number; + /** + * End Step Percent + * @description When the IP-Adapter is last applied (% of total steps) + * @default 1 + */ + end_step_percent?: number; }; /** * IP-Adapter @@ -2602,10 +2614,22 @@ export type components = { ip_adapter_model: components["schemas"]["IPAdapterModelField"]; /** * Weight - * @description The weight of the IP-Adapter. + * @description The weight given to the IP-Adapter * @default 1 */ - weight?: number; + weight?: number | number[]; + /** + * Begin Step Percent + * @description When the IP-Adapter is first applied (% of total steps) + * @default 0 + */ + begin_step_percent?: number; + /** + * End Step Percent + * @description When the IP-Adapter is last applied (% of total steps) + * @default 1 + */ + end_step_percent?: number; /** * Type * @default ip_adapter @@ -7706,18 +7730,6 @@ export type components = { /** Ui Order */ ui_order?: number; }; - /** - * CLIPVisionModelFormat - * @description An enumeration. - * @enum {string} - */ - CLIPVisionModelFormat: "diffusers"; - /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionXLModelFormat * @description An enumeration. @@ -7725,17 +7737,17 @@ export type components = { */ StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; /** - * ControlNetModelFormat + * StableDiffusionOnnxModelFormat * @description An enumeration. * @enum {string} */ - ControlNetModelFormat: "checkpoint" | "diffusers"; + StableDiffusionOnnxModelFormat: "olive" | "onnx"; /** - * IPAdapterModelFormat + * CLIPVisionModelFormat * @description An enumeration. * @enum {string} */ - IPAdapterModelFormat: "invokeai"; + CLIPVisionModelFormat: "diffusers"; /** * StableDiffusion1ModelFormat * @description An enumeration. @@ -7743,11 +7755,23 @@ export type components = { */ StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** - * StableDiffusionOnnxModelFormat + * IPAdapterModelFormat * @description An enumeration. * @enum {string} */ - StableDiffusionOnnxModelFormat: "olive" | "onnx"; + IPAdapterModelFormat: "invokeai"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; + /** + * ControlNetModelFormat + * @description An enumeration. + * @enum {string} + */ + ControlNetModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never;