diff --git a/invokeai/app/invocations/latent.py b/invokeai/app/invocations/latent.py index 90a9137dd3..e9b1425464 100644 --- a/invokeai/app/invocations/latent.py +++ b/invokeai/app/invocations/latent.py @@ -260,7 +260,7 @@ class TextToLatentsInvocation(BaseInvocation): print("type of control input: ", type(self.control)) if (self.control is None): - control_model_name = None + control_model = None control_image_field = None control_weight = None else: diff --git a/invokeai/frontend/web/src/common/util/parseMetadata.ts b/invokeai/frontend/web/src/common/util/parseMetadata.ts index c27833218b..c1be165eac 100644 --- a/invokeai/frontend/web/src/common/util/parseMetadata.ts +++ b/invokeai/frontend/web/src/common/util/parseMetadata.ts @@ -1,5 +1,5 @@ import { forEach, size } from 'lodash-es'; -import { ImageField, LatentsField, ConditioningField } from 'services/api'; +import { ImageField, LatentsField, ConditioningField, ControlField} from 'services/api'; const OBJECT_TYPESTRING = '[object Object]'; const STRING_TYPESTRING = '[object String]'; @@ -98,6 +98,29 @@ const parseConditioningField = ( }; }; +const parseControlField = (controlField: unknown): ControlField | undefined => { + // Must be an object + if (!isObject(controlField)) { + return; + } + + // A ControlField must have a `control` + if (!('control' in controlField)) { + return; + } + console.log(typeof controlField.control); + // A ControlField's `controlnets` must be a array + // TODO: check type - array of tuples + //if (Array.isArray(controlField.control)) { + //return; + // } + + // Build a valid ControlField + return { + control: controlField.control, + }; +}; + type NodeMetadata = { [key: string]: | string @@ -105,7 +128,8 @@ type NodeMetadata = { | boolean | ImageField | LatentsField - | ConditioningField; + | ConditioningField + | ControlField; }; type InvokeAIMetadata = { @@ -131,7 +155,7 @@ export const parseNodeMetadata = ( return; } - // the only valid object types are ImageField, LatentsField and ConditioningField + // the only valid object types are ImageField, LatentsField, ConditioningField, ControlField if (isObject(nodeItem)) { if ('image_name' in nodeItem || 'image_type' in nodeItem) { const imageField = parseImageField(nodeItem); @@ -156,6 +180,14 @@ export const parseNodeMetadata = ( } return; } + + if ('control' in nodeItem) { + const controlField = parseControlField(nodeItem); + if (controlField) { + parsed[nodeKey] = controlField; + } + return; + } } // otherwise we accept any string, number or boolean diff --git a/invokeai/frontend/web/src/features/nodes/components/InputFieldComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/InputFieldComponent.tsx index 9527708c40..f8e9800f76 100644 --- a/invokeai/frontend/web/src/features/nodes/components/InputFieldComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/InputFieldComponent.tsx @@ -7,6 +7,12 @@ import EnumInputFieldComponent from './fields/EnumInputFieldComponent'; import ImageInputFieldComponent from './fields/ImageInputFieldComponent'; import LatentsInputFieldComponent from './fields/LatentsInputFieldComponent'; import ConditioningInputFieldComponent from './fields/ConditioningInputFieldComponent'; +<<<<<<< HEAD +======= +import ControlNetInputFieldComponent from './fields/ControlNetInputFieldComponent'; +import ControlInputFieldComponent from './fields/ControlInputFieldComponent'; + +>>>>>>> 5b9fa636 (Refactored controlnet node to output ControlField that bundles control info.) import ModelInputFieldComponent from './fields/ModelInputFieldComponent'; import NumberInputFieldComponent from './fields/NumberInputFieldComponent'; import StringInputFieldComponent from './fields/StringInputFieldComponent'; @@ -97,6 +103,29 @@ const InputFieldComponent = (props: InputFieldComponentProps) => { ); } +<<<<<<< HEAD +======= + if (type === 'controlnet' && template.type === 'controlnet') { + return ( + + ); + } + + if (type === 'control' && template.type === 'control') { + return ( + + ); + } + +>>>>>>> 5b9fa636 (Refactored controlnet node to output ControlField that bundles control info.) if (type === 'model' && template.type === 'model') { return ( +) => { + const { nodeId, field } = props; + + return null; +}; + +export default memo(ControlInputFieldComponent); diff --git a/invokeai/frontend/web/src/features/nodes/types/constants.ts b/invokeai/frontend/web/src/features/nodes/types/constants.ts index 7e4dadc21d..603f68f35e 100644 --- a/invokeai/frontend/web/src/features/nodes/types/constants.ts +++ b/invokeai/frontend/web/src/features/nodes/types/constants.ts @@ -15,6 +15,7 @@ export const FIELD_TYPE_MAP: Record = { array: 'array', item: 'item', ColorField: 'color', + ControlField: 'control', }; const COLOR_TOKEN_VALUE = 500; @@ -22,6 +23,9 @@ const COLOR_TOKEN_VALUE = 500; const getColorTokenCssVariable = (color: string) => `var(--invokeai-colors-${color}-${COLOR_TOKEN_VALUE})`; +// @ts-ignore +// @ts-ignore +// @ts-ignore export const FIELDS: Record = { integer: { color: 'red', @@ -71,6 +75,12 @@ export const FIELDS: Record = { title: 'Conditioning', description: 'Conditioning may be passed between nodes.', }, + control: { + color: 'cyan', + colorCssVar: getColorTokenCssVariable('cyan'), // TODO: no free color left + title: 'Control', + description: 'Control info passed between nodes.', + }, model: { color: 'teal', colorCssVar: getColorTokenCssVariable('teal'), diff --git a/invokeai/frontend/web/src/features/nodes/types/types.ts b/invokeai/frontend/web/src/features/nodes/types/types.ts index efb4a5518d..998d8a7956 100644 --- a/invokeai/frontend/web/src/features/nodes/types/types.ts +++ b/invokeai/frontend/web/src/features/nodes/types/types.ts @@ -61,6 +61,7 @@ export type FieldType = | 'image' | 'latents' | 'conditioning' + | 'control' | 'model' | 'array' | 'item' @@ -82,6 +83,7 @@ export type InputFieldValue = | ImageInputFieldValue | LatentsInputFieldValue | ConditioningInputFieldValue + | ControlInputFieldValue | EnumInputFieldValue | ModelInputFieldValue | ArrayInputFieldValue @@ -102,6 +104,7 @@ export type InputFieldTemplate = | ImageInputFieldTemplate | LatentsInputFieldTemplate | ConditioningInputFieldTemplate + | ControlInputFieldTemplate | EnumInputFieldTemplate | ModelInputFieldTemplate | ArrayInputFieldTemplate @@ -177,6 +180,10 @@ export type LatentsInputFieldValue = FieldValueBase & { export type ConditioningInputFieldValue = FieldValueBase & { type: 'conditioning'; +}; + +export type ControlInputFieldValue = FieldValueBase & { + type: 'control'; value?: undefined; }; @@ -262,6 +269,11 @@ export type ConditioningInputFieldTemplate = InputFieldTemplateBase & { type: 'conditioning'; }; +export type ControlInputFieldTemplate = InputFieldTemplateBase & { + default: undefined; + type: 'control'; +}; + export type EnumInputFieldTemplate = InputFieldTemplateBase & { default: string | number; type: 'enum'; diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts index 11f0087488..28a9c8ec7c 100644 --- a/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts +++ b/invokeai/frontend/web/src/features/nodes/util/fieldTemplateBuilders.ts @@ -10,6 +10,7 @@ import { IntegerInputFieldTemplate, LatentsInputFieldTemplate, ConditioningInputFieldTemplate, + ControlInputFieldTemplate, StringInputFieldTemplate, ModelInputFieldTemplate, ArrayInputFieldTemplate, @@ -215,6 +216,21 @@ const buildConditioningInputFieldTemplate = ({ return template; }; +const buildControlInputFieldTemplate = ({ + schemaObject, + baseField, +}: BuildInputFieldArg): ControlInputFieldTemplate => { + const template: ControlInputFieldTemplate = { + ...baseField, + type: 'control', + inputRequirement: 'always', + inputKind: 'connection', + default: schemaObject.default ?? undefined, + }; + + return template; +}; + const buildEnumInputFieldTemplate = ({ schemaObject, baseField, @@ -331,6 +347,9 @@ export const buildInputFieldTemplate = ( if (['conditioning'].includes(fieldType)) { return buildConditioningInputFieldTemplate({ schemaObject, baseField }); } + if (['control'].includes(fieldType)) { + return buildControlInputFieldTemplate({ schemaObject, baseField }); + } if (['model'].includes(fieldType)) { return buildModelInputFieldTemplate({ schemaObject, baseField }); } diff --git a/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts b/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts index 9221e5f7ac..0b10a3e464 100644 --- a/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts +++ b/invokeai/frontend/web/src/features/nodes/util/fieldValueBuilders.ts @@ -52,6 +52,10 @@ export const buildInputFieldValue = ( fieldValue.value = undefined; } + if (template.type === 'control') { + fieldValue.value = undefined; + } + if (template.type === 'model') { fieldValue.value = undefined; }