From 94591840a79df2f4399a4ea5b5e8c12357cf9d58 Mon Sep 17 00:00:00 2001 From: Ryan Dick Date: Fri, 6 Oct 2023 14:36:26 -0400 Subject: [PATCH] Frontend changes to enable multiple IP-Adapters in the workflow editor. --- .../fields/inputs/IPAdapterInputField.tsx | 6 ++- .../web/src/features/nodes/types/constants.ts | 16 +++++++ .../web/src/features/nodes/types/types.ts | 37 ++++++++++++++++ .../nodes/util/fieldTemplateBuilders.ts | 32 ++++++++++++++ .../features/nodes/util/fieldValueBuilders.ts | 2 + .../frontend/web/src/services/api/schema.d.ts | 44 +++++++++++-------- 6 files changed, 116 insertions(+), 21 deletions(-) diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/IPAdapterInputField.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/IPAdapterInputField.tsx index 5d5567e515..efeffe5723 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/IPAdapterInputField.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/IPAdapterInputField.tsx @@ -2,13 +2,15 @@ import { IPAdapterInputFieldTemplate, IPAdapterInputFieldValue, FieldComponentProps, + IPAdapterPolymorphicInputFieldValue, + IPAdapterPolymorphicInputFieldTemplate, } from 'features/nodes/types/types'; import { memo } from 'react'; const IPAdapterInputFieldComponent = ( _props: FieldComponentProps< - IPAdapterInputFieldValue, - IPAdapterInputFieldTemplate + IPAdapterInputFieldValue | IPAdapterPolymorphicInputFieldValue, + IPAdapterInputFieldTemplate | IPAdapterPolymorphicInputFieldTemplate > ) => { return null; diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts index 9c2470c57c..564456cea9 100644 --- a/invokeai/frontend/web/src/features/nodes/types/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts @@ -32,6 +32,7 @@ export const COLLECTION_TYPES: FieldType[] = [ 'ControlCollection', 'ColorCollection', 'T2IAdapterCollection', + 'IPAdapterCollection', ]; export const POLYMORPHIC_TYPES: FieldType[] = [ @@ -45,6 +46,7 @@ export const POLYMORPHIC_TYPES: FieldType[] = [ 'ControlPolymorphic', 'ColorPolymorphic', 'T2IAdapterPolymorphic', + 'IPAdapterPolymorphic', ]; export const MODEL_TYPES: FieldType[] = [ @@ -60,6 +62,7 @@ export const MODEL_TYPES: FieldType[] = [ 'VaeField', 'ClipField', 'T2IAdapterModelField', + 'IPAdapterModelField', ]; export const COLLECTION_MAP: FieldTypeMapWithNumber = { @@ -74,6 +77,7 @@ export const COLLECTION_MAP: FieldTypeMapWithNumber = { ControlField: 'ControlCollection', ColorField: 'ColorCollection', T2IAdapterField: 'T2IAdapterCollection', + IPAdapterField: 'IPAdapterCollection', }; export const isCollectionItemType = ( itemType: string | undefined @@ -92,6 +96,7 @@ export const SINGLE_TO_POLYMORPHIC_MAP: FieldTypeMapWithNumber = { ControlField: 'ControlPolymorphic', ColorField: 'ColorPolymorphic', T2IAdapterField: 'T2IAdapterPolymorphic', + IPAdapterField: 'IPAdapterPolymorphic', }; export const POLYMORPHIC_TO_SINGLE_MAP: FieldTypeMap = { @@ -105,6 +110,7 @@ export const POLYMORPHIC_TO_SINGLE_MAP: FieldTypeMap = { ControlPolymorphic: 'ControlField', ColorPolymorphic: 'ColorField', T2IAdapterPolymorphic: 'T2IAdapterField', + IPAdapterPolymorphic: 'IPAdapterField', }; export const TYPES_WITH_INPUT_COMPONENTS: FieldType[] = [ @@ -278,6 +284,11 @@ export const FIELDS: Record = { description: t('nodes.integerPolymorphicDescription'), title: t('nodes.integerPolymorphic'), }, + IPAdapterCollection: { + color: 'teal.500', + description: t('nodes.ipAdapterCollectionDescription'), + title: t('nodes.ipAdapterCollection'), + }, IPAdapterField: { color: 'teal.500', description: 'IP-Adapter info passed between nodes.', @@ -288,6 +299,11 @@ export const FIELDS: Record = { description: 'IP-Adapter model', title: 'IP-Adapter Model', }, + IPAdapterPolymorphic: { + color: 'teal.500', + description: 'IP-Adapter info passed between nodes.', + title: 'IP-Adapter Polymorphic', + }, LatentsCollection: { color: 'pink.500', description: t('nodes.latentsCollectionDescription'), diff --git a/invokeai/frontend/web/src/features/nodes/types/types.ts b/invokeai/frontend/web/src/features/nodes/types/types.ts index d65eb1b21e..24ba81c37d 100644 --- a/invokeai/frontend/web/src/features/nodes/types/types.ts +++ b/invokeai/frontend/web/src/features/nodes/types/types.ts @@ -100,8 +100,10 @@ export const zFieldType = z.enum([ 'integer', 'IntegerCollection', 'IntegerPolymorphic', + 'IPAdapterCollection', 'IPAdapterField', 'IPAdapterModelField', + 'IPAdapterPolymorphic', 'LatentsCollection', 'LatentsField', 'LatentsPolymorphic', @@ -430,6 +432,24 @@ export type IPAdapterInputFieldValue = z.infer< typeof zIPAdapterInputFieldValue >; +export const zIPAdapterPolymorphicInputFieldValue = zInputFieldValueBase.extend( + { + type: z.literal('IPAdapterPolymorphic'), + value: z.union([zIPAdapterField, z.array(zIPAdapterField)]).optional(), + } +); +export type IPAdapterPolymorphicInputFieldValue = z.infer< + typeof zT2IAdapterPolymorphicInputFieldValue +>; + +export const zIPAdapterCollectionInputFieldValue = zInputFieldValueBase.extend({ + type: z.literal('IPAdapterCollection'), + value: z.array(zIPAdapterField).optional(), +}); +export type IPAdapterCollectionInputFieldValue = z.infer< + typeof zIPAdapterCollectionInputFieldValue +>; + export const zT2IAdapterModel = zModelIdentifier; export type T2IAdapterModel = z.infer; @@ -734,6 +754,8 @@ export const zInputFieldValue = z.discriminatedUnion('type', [ zIntegerInputFieldValue, zIPAdapterInputFieldValue, zIPAdapterModelInputFieldValue, + zIPAdapterCollectionInputFieldValue, + zIPAdapterPolymorphicInputFieldValue, zLatentsInputFieldValue, zLatentsCollectionInputFieldValue, zLatentsPolymorphicInputFieldValue, @@ -950,6 +972,19 @@ export type IPAdapterInputFieldTemplate = InputFieldTemplateBase & { type: 'IPAdapterField'; }; +export type IPAdapterCollectionInputFieldTemplate = InputFieldTemplateBase & { + default: undefined; + type: 'IPAdapterCollection'; + item_default?: IPAdapterField; +}; + +export type IPAdapterPolymorphicInputFieldTemplate = Omit< + IPAdapterInputFieldTemplate, + 'type' +> & { + type: 'IPAdapterPolymorphic'; +}; + export type T2IAdapterInputFieldTemplate = InputFieldTemplateBase & { default: undefined; type: 'T2IAdapterField'; @@ -1088,7 +1123,9 @@ export type InputFieldTemplate = | IntegerPolymorphicInputFieldTemplate | IntegerInputFieldTemplate | IPAdapterInputFieldTemplate + | IPAdapterCollectionInputFieldTemplate | IPAdapterModelInputFieldTemplate + | IPAdapterPolymorphicInputFieldTemplate | LatentsInputFieldTemplate | LatentsCollectionInputFieldTemplate | LatentsPolymorphicInputFieldTemplate diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts index 74bbe2d3ac..1f7fe81620 100644 --- a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts +++ b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts @@ -60,8 +60,11 @@ import { ImageField, LatentsField, ConditioningField, + IPAdapterField, IPAdapterInputFieldTemplate, IPAdapterModelInputFieldTemplate, + IPAdapterPolymorphicInputFieldTemplate, + IPAdapterCollectionInputFieldTemplate, T2IAdapterField, T2IAdapterInputFieldTemplate, T2IAdapterModelInputFieldTemplate, @@ -709,6 +712,33 @@ const buildIPAdapterInputFieldTemplate = ({ return template; }; +const buildIPAdapterPolymorphicInputFieldTemplate = ({ + schemaObject, + baseField, +}: BuildInputFieldArg): IPAdapterPolymorphicInputFieldTemplate => { + const template: IPAdapterPolymorphicInputFieldTemplate = { + ...baseField, + type: 'IPAdapterPolymorphic', + default: schemaObject.default ?? undefined, + }; + + return template; +}; + +const buildIPAdapterCollectionInputFieldTemplate = ({ + schemaObject, + baseField, +}: BuildInputFieldArg): IPAdapterCollectionInputFieldTemplate => { + const template: IPAdapterCollectionInputFieldTemplate = { + ...baseField, + type: 'IPAdapterCollection', + default: schemaObject.default ?? [], + item_default: (schemaObject.item_default as IPAdapterField) ?? undefined, + }; + + return template; +}; + const buildT2IAdapterInputFieldTemplate = ({ schemaObject, baseField, @@ -955,8 +985,10 @@ const TEMPLATE_BUILDER_MAP: { integer: buildIntegerInputFieldTemplate, IntegerCollection: buildIntegerCollectionInputFieldTemplate, IntegerPolymorphic: buildIntegerPolymorphicInputFieldTemplate, + IPAdapterCollection: buildIPAdapterCollectionInputFieldTemplate, IPAdapterField: buildIPAdapterInputFieldTemplate, IPAdapterModelField: buildIPAdapterModelInputFieldTemplate, + IPAdapterPolymorphic: buildIPAdapterPolymorphicInputFieldTemplate, LatentsCollection: buildLatentsCollectionInputFieldTemplate, LatentsField: buildLatentsInputFieldTemplate, LatentsPolymorphic: buildLatentsPolymorphicInputFieldTemplate, diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts index 532449eeb6..97f520379a 100644 --- a/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts +++ b/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts @@ -31,8 +31,10 @@ const FIELD_VALUE_FALLBACK_MAP: { integer: 0, IntegerCollection: [], IntegerPolymorphic: 0, + IPAdapterCollection: [], IPAdapterField: undefined, IPAdapterModelField: undefined, + IPAdapterPolymorphic: undefined, LatentsCollection: [], LatentsField: undefined, LatentsPolymorphic: undefined, diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 1db22fd6b4..b4f2394271 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -2403,7 +2403,7 @@ export type components = { * IP-Adapter * @description IP-Adapter to apply */ - ip_adapter?: components["schemas"]["IPAdapterField"]; + ip_adapter?: components["schemas"]["IPAdapterField"] | components["schemas"]["IPAdapterField"][]; /** * T2I-Adapter * @description T2I-Adapter(s) to apply @@ -2617,6 +2617,12 @@ export type components = { * @enum {string} */ model_name?: "RealESRGAN_x4plus.pth" | "RealESRGAN_x4plus_anime_6B.pth" | "ESRGAN_SRx4_DF2KOST_official-ff704c30.pth" | "RealESRGAN_x2plus.pth"; + /** + * Tile Size + * @description Tile size for tiled ESRGAN upscaling (0=tiling disabled) + * @default 400 + */ + tile_size?: number; /** * Type * @default esrgan @@ -9684,18 +9690,24 @@ export type components = { /** Ui Order */ ui_order?: number; }; - /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** * T2IAdapterModelFormat * @description An enumeration. * @enum {string} */ T2IAdapterModelFormat: "diffusers"; + /** + * ControlNetModelFormat + * @description An enumeration. + * @enum {string} + */ + ControlNetModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusion1ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionOnnxModelFormat * @description An enumeration. @@ -9708,30 +9720,24 @@ export type components = { * @enum {string} */ CLIPVisionModelFormat: "diffusers"; - /** - * ControlNetModelFormat - * @description An enumeration. - * @enum {string} - */ - ControlNetModelFormat: "checkpoint" | "diffusers"; /** * StableDiffusionXLModelFormat * @description An enumeration. * @enum {string} */ StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; /** * IPAdapterModelFormat * @description An enumeration. * @enum {string} */ IPAdapterModelFormat: "invokeai"; - /** - * StableDiffusion1ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never;