diff --git a/invokeai/app/invocations/baseinvocation.py b/invokeai/app/invocations/baseinvocation.py index 22e68ea3cb..51849dcbcc 100644 --- a/invokeai/app/invocations/baseinvocation.py +++ b/invokeai/app/invocations/baseinvocation.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) +# Copyright (c) 2022 Kyle Schouviller (https://github.com/kyle0654) and the InvokeAI team from __future__ import annotations @@ -8,7 +8,7 @@ from abc import ABC, abstractmethod from enum import Enum from inspect import signature from types import UnionType -from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, Literal, Optional, Type, TypeVar, Union +from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, Literal, Optional, Type, TypeVar, Union, cast import semver from pydantic import BaseModel, ConfigDict, Field, RootModel, TypeAdapter, create_model @@ -26,6 +26,8 @@ if TYPE_CHECKING: logger = InvokeAILogger.get_logger() +CUSTOM_NODE_PACK_SUFFIX = "__invokeai-custom-node" + class InvalidVersionError(ValueError): pass @@ -432,10 +434,10 @@ class UIConfigBase(BaseModel): tags: Optional[list[str]] = Field(default_factory=None, description="The node's tags") title: Optional[str] = Field(default=None, description="The node's display name") category: Optional[str] = Field(default=None, description="The node's category") - version: Optional[str] = Field( - default=None, + version: str = Field( description='The node\'s version. Should be a valid semver string e.g. "1.0.0" or "3.8.13".', ) + node_pack: Optional[str] = Field(default=None, description="Whether or not this is a custom node") model_config = ConfigDict( validate_assignment=True, @@ -591,14 +593,16 @@ class BaseInvocation(ABC, BaseModel): @staticmethod def json_schema_extra(schema: dict[str, Any], model_class: Type[BaseModel], *args, **kwargs) -> None: """Adds various UI-facing attributes to the invocation's OpenAPI schema.""" - uiconfig = getattr(model_class, "UIConfig", None) - if uiconfig and hasattr(uiconfig, "title"): - schema["title"] = uiconfig.title - if uiconfig and hasattr(uiconfig, "tags"): - schema["tags"] = uiconfig.tags - if uiconfig and hasattr(uiconfig, "category"): - schema["category"] = uiconfig.category - if uiconfig and hasattr(uiconfig, "version"): + uiconfig = cast(UIConfigBase | None, getattr(model_class, "UIConfig", None)) + if uiconfig is not None: + if uiconfig.title is not None: + schema["title"] = uiconfig.title + if uiconfig.tags is not None: + schema["tags"] = uiconfig.tags + if uiconfig.category is not None: + schema["category"] = uiconfig.category + if uiconfig.node_pack is not None: + schema["node_pack"] = uiconfig.node_pack schema["version"] = uiconfig.version if "required" not in schema or not isinstance(schema["required"], list): schema["required"] = [] @@ -796,15 +800,20 @@ def invocation( validate_fields(cls.model_fields, invocation_type) # Add OpenAPI schema extras - uiconf_name = cls.__qualname__ + ".UIConfig" - if not hasattr(cls, "UIConfig") or cls.UIConfig.__qualname__ != uiconf_name: - cls.UIConfig = type(uiconf_name, (UIConfigBase,), {}) - if title is not None: - cls.UIConfig.title = title - if tags is not None: - cls.UIConfig.tags = tags - if category is not None: - cls.UIConfig.category = category + uiconfig_name = cls.__qualname__ + ".UIConfig" + if not hasattr(cls, "UIConfig") or cls.UIConfig.__qualname__ != uiconfig_name: + cls.UIConfig = type(uiconfig_name, (UIConfigBase,), {}) + cls.UIConfig.title = title + cls.UIConfig.tags = tags + cls.UIConfig.category = category + + # Grab the node pack's name from the module name, if it's a custom node + module_name = cls.__module__.split(".")[0] + if module_name.endswith(CUSTOM_NODE_PACK_SUFFIX): + cls.UIConfig.node_pack = module_name.split(CUSTOM_NODE_PACK_SUFFIX)[0] + else: + cls.UIConfig.node_pack = None + if version is not None: try: semver.Version.parse(version) @@ -814,6 +823,7 @@ def invocation( else: logger.warn(f'No version specified for node "{invocation_type}", using "1.0.0"') cls.UIConfig.version = "1.0.0" + if use_cache is not None: cls.model_fields["use_cache"].default = use_cache diff --git a/invokeai/app/invocations/custom_nodes/init.py b/invokeai/app/invocations/custom_nodes/init.py index a379a35fbf..4503287cdb 100644 --- a/invokeai/app/invocations/custom_nodes/init.py +++ b/invokeai/app/invocations/custom_nodes/init.py @@ -6,6 +6,7 @@ import sys from importlib.util import module_from_spec, spec_from_file_location from pathlib import Path +from invokeai.app.invocations.baseinvocation import CUSTOM_NODE_PACK_SUFFIX from invokeai.backend.util.logging import InvokeAILogger logger = InvokeAILogger.get_logger() @@ -32,8 +33,8 @@ for d in Path(__file__).parent.iterdir(): if module_name in globals(): continue - # we have a legit module to import - spec = spec_from_file_location(module_name, init.absolute()) + # load the module, appending adding a suffix to identify it as a custom node pack + spec = spec_from_file_location(f"{module_name}{CUSTOM_NODE_PACK_SUFFIX}", init.absolute()) if spec is None or spec.loader is None: logger.warn(f"Could not load {init}") diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index a1b2c2b6e7..3e7e26d9a9 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -160,6 +160,7 @@ "trainingDesc2": "InvokeAI already supports training custom embeddourings using Textual Inversion using the main script.", "txt2img": "Text To Image", "unifiedCanvas": "Unified Canvas", + "unknown": "Unknown", "upload": "Upload" }, "controlnet": { @@ -802,6 +803,7 @@ "cannotConnectOutputToOutput": "Cannot connect output to output", "cannotConnectToSelf": "Cannot connect to self", "cannotDuplicateConnection": "Cannot create duplicate connections", + "nodePack": "Node pack", "clipField": "Clip", "clipFieldDescription": "Tokenizer and text_encoder submodels.", "collection": "Collection", @@ -966,6 +968,7 @@ "unableToParseNode": "Unable to parse node", "unableToUpdateNode": "Unable to update node", "unableToValidateWorkflow": "Unable to Validate Workflow", + "unableToMigrateWorkflow": "Unable to Migrate Workflow", "unknownErrorValidatingWorkflow": "Unknown error validating workflow", "inputFieldTypeParseError": "Unable to parse type of input field {{node}}.{{field}} ({{message}})", "outputFieldTypeParseError": "Unable to parse type of output field {{node}}.{{field}} ({{message}})", @@ -979,9 +982,9 @@ "unhandledInputProperty": "Unhandled input property", "unhandledOutputProperty": "Unhandled output property", "unknownField": "Unknown field", - "unknownFieldType": "$t(nodes.unknownField) type", + "unknownFieldType": "$t(nodes.unknownField) type: {{type}}", "unknownNode": "Unknown Node", - "unknownNodeType": "$t(nodes.unknownNode) type", + "unknownNodeType": "Unknown node type", "unknownTemplate": "Unknown Template", "unknownInput": "Unknown input: {{name}}", "unkownInvocation": "Unknown Invocation type", diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoadRequested.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoadRequested.ts index 20d0ac0773..bd677ca6f1 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoadRequested.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/workflowLoadRequested.ts @@ -3,7 +3,10 @@ import { parseify } from 'common/util/serialize'; import { workflowLoadRequested } from 'features/nodes/store/actions'; import { workflowLoaded } from 'features/nodes/store/nodesSlice'; import { $flow } from 'features/nodes/store/reactFlowInstance'; -import { WorkflowVersionError } from 'features/nodes/types/error'; +import { + WorkflowMigrationError, + WorkflowVersionError, +} from 'features/nodes/types/error'; import { validateWorkflow } from 'features/nodes/util/workflow/validateWorkflow'; import { addToast } from 'features/system/store/systemSlice'; import { makeToast } from 'features/system/util/makeToast'; @@ -67,6 +70,18 @@ export const addWorkflowLoadRequestedListener = () => { }) ) ); + } else if (e instanceof WorkflowMigrationError) { + // There was a problem migrating the workflow to the latest version + log.error({ error: parseify(e) }, e.message); + dispatch( + addToast( + makeToast({ + title: t('nodes.unableToValidateWorkflow'), + status: 'error', + description: e.message, + }) + ) + ); } else if (e instanceof z.ZodError) { // There was a problem validating the workflow itself const { message } = fromZodError(e, { diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeInfoIcon.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeInfoIcon.tsx index a439538075..fbf5a1c8dc 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeInfoIcon.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeInfoIcon.tsx @@ -24,6 +24,7 @@ const InvocationNodeInfoIcon = ({ nodeId }: Props) => { { {title} + {nodeTemplate?.nodePack && ( + + {t('nodes.nodePack')}: {nodeTemplate.nodePack} + + )} {nodeTemplate?.description} diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeUnknownFallback.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeUnknownFallback.tsx index cd95e2f79f..efdb7b6532 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeUnknownFallback.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeUnknownFallback.tsx @@ -1,9 +1,10 @@ -import { Box, Flex, Text } from '@chakra-ui/react'; +import { Flex, Text } from '@chakra-ui/react'; +import { useNodePack } from 'features/nodes/hooks/useNodePack'; import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants'; import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; import NodeCollapseButton from '../common/NodeCollapseButton'; import NodeWrapper from '../common/NodeWrapper'; -import { useTranslation } from 'react-i18next'; type Props = { nodeId: string; @@ -21,6 +22,7 @@ const InvocationNodeUnknownFallback = ({ selected, }: Props) => { const { t } = useTranslation(); + const nodePack = useNodePack(nodeId); return ( - - {t('nodes.unknownNodeType')}: - - {type} + + + {t('nodes.unknownNodeType')}:{' '} + + {type} + - + {nodePack && ( + + {t('nodes.nodePack')}:{' '} + + {nodePack} + + + )} + )} diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx index ad2caf1b57..9b47c42af9 100644 --- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldRenderer.tsx @@ -298,7 +298,7 @@ const InputFieldRenderer = ({ nodeId, fieldName }: InputFieldProps) => { _dark: { color: 'error.300' }, }} > - {t('nodes.unknownFieldType')}: {fieldInstance?.type.name} + {t('nodes.unknownFieldType', { type: fieldInstance?.type.name })} ); diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useNodePack.ts b/invokeai/frontend/web/src/features/nodes/hooks/useNodePack.ts new file mode 100644 index 0000000000..da815c1657 --- /dev/null +++ b/invokeai/frontend/web/src/features/nodes/hooks/useNodePack.ts @@ -0,0 +1,27 @@ +import { createSelector } from '@reduxjs/toolkit'; +import { stateSelector } from 'app/store/store'; +import { useAppSelector } from 'app/store/storeHooks'; +import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import { useMemo } from 'react'; +import { isInvocationNode } from '../types/invocation'; + +export const useNodePack = (nodeId: string) => { + const selector = useMemo( + () => + createSelector( + stateSelector, + ({ nodes }) => { + const node = nodes.nodes.find((node) => node.id === nodeId); + if (!isInvocationNode(node)) { + return false; + } + return node.data.nodePack; + }, + defaultSelectorOptions + ), + [nodeId] + ); + + const title = useAppSelector(selector); + return title; +}; diff --git a/invokeai/frontend/web/src/features/nodes/types/error.ts b/invokeai/frontend/web/src/features/nodes/types/error.ts index b7ffb753bc..e520b7710d 100644 --- a/invokeai/frontend/web/src/features/nodes/types/error.ts +++ b/invokeai/frontend/web/src/features/nodes/types/error.ts @@ -12,6 +12,20 @@ export class WorkflowVersionError extends Error { this.name = this.constructor.name; } } +/** + * Workflow Migration Error + * Raised when a workflow migration fails. + */ +export class WorkflowMigrationError extends Error { + /** + * Create WorkflowMigrationError + * @param {String} message + */ + constructor(message: string) { + super(message); + this.name = this.constructor.name; + } +} /** * Unable to Update Node Error diff --git a/invokeai/frontend/web/src/features/nodes/types/invocation.ts b/invokeai/frontend/web/src/features/nodes/types/invocation.ts index 5d22e64545..3af64c7705 100644 --- a/invokeai/frontend/web/src/features/nodes/types/invocation.ts +++ b/invokeai/frontend/web/src/features/nodes/types/invocation.ts @@ -21,6 +21,7 @@ export const zInvocationTemplate = z.object({ withWorkflow: z.boolean(), version: zSemVer, useCache: z.boolean(), + nodePack: z.string().min(1).nullish(), }); export type InvocationTemplate = z.infer; // #endregion @@ -36,6 +37,7 @@ export const zInvocationNodeData = z.object({ isIntermediate: z.boolean(), useCache: z.boolean(), version: zSemVer, + nodePack: z.string().min(1).nullish(), inputs: z.record(zFieldInputInstance), outputs: z.record(zFieldOutputInstance), }); diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts index 04b3f66e7d..4755752145 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts @@ -82,6 +82,7 @@ export const parseSchema = ( const tags = schema.tags ?? []; const description = schema.description ?? ''; const version = schema.version; + const nodePack = schema.node_pack; let withWorkflow = false; const inputs = reduce( @@ -257,6 +258,7 @@ export const parseSchema = ( outputs, useCache, withWorkflow, + nodePack, }; Object.assign(invocationsAccumulator, { [type]: invocation }); diff --git a/invokeai/frontend/web/src/features/nodes/util/workflow/migrations.ts b/invokeai/frontend/web/src/features/nodes/util/workflow/migrations.ts index 5428ac9861..cba85ea857 100644 --- a/invokeai/frontend/web/src/features/nodes/util/workflow/migrations.ts +++ b/invokeai/frontend/web/src/features/nodes/util/workflow/migrations.ts @@ -1,7 +1,14 @@ +import { $store } from 'app/store/nanostores/store'; +import { RootState } from 'app/store/store'; +import { FieldType } from 'features/nodes/types/field'; +import { InvocationNodeData } from 'features/nodes/types/invocation'; import { t } from 'i18next'; -import { forEach, isString } from 'lodash-es'; +import { forEach } from 'lodash-es'; import { z } from 'zod'; -import { WorkflowVersionError } from '../../types/error'; +import { + WorkflowMigrationError, + WorkflowVersionError, +} from '../../types/error'; import { zSemVer } from '../../types/semver'; import { FIELD_TYPE_V1_TO_FIELD_TYPE_V2_MAPPING } from '../../types/v1/fieldTypeMap'; import { WorkflowV1, zWorkflowV1 } from '../../types/v1/workflowV1'; @@ -20,22 +27,39 @@ const zWorkflowMetaVersion = z.object({ * Migrates a workflow from V1 to V2. */ const migrateV1toV2 = (workflowToMigrate: WorkflowV1): WorkflowV2 => { + const invocationTemplates = ($store.get()?.getState() as RootState).nodes + .nodeTemplates; workflowToMigrate.nodes.forEach((node) => { if (node.type === 'invocation') { + // Migrate field types forEach(node.data.inputs, (input) => { - if (!isString(input.type)) { - return; + const newFieldType = FIELD_TYPE_V1_TO_FIELD_TYPE_V2_MAPPING[input.type]; + if (!newFieldType) { + throw new WorkflowMigrationError( + t('nodes.unknownFieldType', { type: input.type }) + ); } - (input.type as unknown) = - FIELD_TYPE_V1_TO_FIELD_TYPE_V2_MAPPING[input.type]; + // Cast as the V2 type + (input.type as unknown as FieldType) = newFieldType; }); forEach(node.data.outputs, (output) => { - if (!isString(output.type)) { - return; - } - (output.type as unknown) = + const newFieldType = FIELD_TYPE_V1_TO_FIELD_TYPE_V2_MAPPING[output.type]; + if (!newFieldType) { + throw new WorkflowMigrationError( + t('nodes.unknownFieldType', { type: output.type }) + ); + } + // Cast as the V2 type + (output.type as unknown as FieldType) = newFieldType; }); + // Migrate nodePack + const invocationTemplate = invocationTemplates[node.data.type]; + const nodePack = invocationTemplate + ? invocationTemplate.nodePack + : t('common.unknown'); + // Cast as the V2 type + (node.data as unknown as InvocationNodeData).nodePack = nodePack; } }); (workflowToMigrate.meta.version as WorkflowV2['meta']['version']) = '2.0.0'; @@ -49,6 +73,7 @@ export const parseAndMigrateWorkflow = (data: unknown): WorkflowV2 => { const workflowVersionResult = zWorkflowMetaVersion.safeParse(data); if (!workflowVersionResult.success) { + console.log(data); throw new WorkflowVersionError(t('nodes.unableToGetWorkflowVersion')); } diff --git a/invokeai/frontend/web/src/services/api/schema.d.ts b/invokeai/frontend/web/src/services/api/schema.d.ts index 5d5b382c4c..b4f9db1370 100644 --- a/invokeai/frontend/web/src/services/api/schema.d.ts +++ b/invokeai/frontend/web/src/services/api/schema.d.ts @@ -3220,7 +3220,7 @@ export type components = { * @description The nodes in this graph */ nodes?: { - [key: string]: components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["LinearUIOutputInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["RangeInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["StepParamEasingInvocation"]; + [key: string]: components["schemas"]["ImageWatermarkInvocation"] | components["schemas"]["CollectInvocation"] | components["schemas"]["ScaleLatentsInvocation"] | components["schemas"]["SDXLLoraLoaderInvocation"] | components["schemas"]["ONNXLatentsToImageInvocation"] | components["schemas"]["StringJoinThreeInvocation"] | components["schemas"]["ImageChannelOffsetInvocation"] | components["schemas"]["FloatToIntegerInvocation"] | components["schemas"]["MainModelLoaderInvocation"] | components["schemas"]["SDXLModelLoaderInvocation"] | components["schemas"]["StringSplitInvocation"] | components["schemas"]["ImageResizeInvocation"] | components["schemas"]["CompelInvocation"] | components["schemas"]["FloatInvocation"] | components["schemas"]["StringSplitNegInvocation"] | components["schemas"]["RandomIntInvocation"] | components["schemas"]["LoraLoaderInvocation"] | components["schemas"]["ImageNSFWBlurInvocation"] | components["schemas"]["CV2InfillInvocation"] | components["schemas"]["LatentsInvocation"] | components["schemas"]["IterateInvocation"] | components["schemas"]["LineartImageProcessorInvocation"] | components["schemas"]["AddInvocation"] | components["schemas"]["MediapipeFaceProcessorInvocation"] | components["schemas"]["ImageInverseLerpInvocation"] | components["schemas"]["DivideInvocation"] | components["schemas"]["LeresImageProcessorInvocation"] | components["schemas"]["RoundInvocation"] | components["schemas"]["OpenposeImageProcessorInvocation"] | components["schemas"]["T2IAdapterInvocation"] | components["schemas"]["ImageBlurInvocation"] | components["schemas"]["FaceOffInvocation"] | components["schemas"]["RangeOfSizeInvocation"] | components["schemas"]["NoiseInvocation"] | components["schemas"]["ResizeLatentsInvocation"] | components["schemas"]["MaskFromAlphaInvocation"] | components["schemas"]["RandomFloatInvocation"] | components["schemas"]["CreateDenoiseMaskInvocation"] | components["schemas"]["MultiplyInvocation"] | components["schemas"]["ImageInvocation"] | components["schemas"]["StringReplaceInvocation"] | components["schemas"]["FaceMaskInvocation"] | components["schemas"]["ImageToLatentsInvocation"] | components["schemas"]["DynamicPromptInvocation"] | components["schemas"]["OnnxModelLoaderInvocation"] | components["schemas"]["SaveImageInvocation"] | components["schemas"]["TileResamplerProcessorInvocation"] | components["schemas"]["VaeLoaderInvocation"] | components["schemas"]["ColorCorrectInvocation"] | components["schemas"]["MaskEdgeInvocation"] | components["schemas"]["FreeUInvocation"] | components["schemas"]["MidasDepthImageProcessorInvocation"] | components["schemas"]["ColorInvocation"] | components["schemas"]["LineartAnimeImageProcessorInvocation"] | components["schemas"]["ControlNetInvocation"] | components["schemas"]["ImageHueAdjustmentInvocation"] | components["schemas"]["SegmentAnythingProcessorInvocation"] | components["schemas"]["ColorMapImageProcessorInvocation"] | components["schemas"]["ImageScaleInvocation"] | components["schemas"]["LaMaInfillInvocation"] | components["schemas"]["ClipSkipInvocation"] | components["schemas"]["InfillPatchMatchInvocation"] | components["schemas"]["ContentShuffleImageProcessorInvocation"] | components["schemas"]["CvInpaintInvocation"] | components["schemas"]["SeamlessModeInvocation"] | components["schemas"]["FloatLinearRangeInvocation"] | components["schemas"]["BlendLatentsInvocation"] | components["schemas"]["ConditioningInvocation"] | components["schemas"]["ImageChannelInvocation"] | components["schemas"]["InfillTileInvocation"] | components["schemas"]["FloatMathInvocation"] | components["schemas"]["IntegerCollectionInvocation"] | components["schemas"]["SubtractInvocation"] | components["schemas"]["LatentsCollectionInvocation"] | components["schemas"]["ImageChannelMultiplyInvocation"] | components["schemas"]["SDXLRefinerModelLoaderInvocation"] | components["schemas"]["SDXLRefinerCompelPromptInvocation"] | components["schemas"]["NormalbaeImageProcessorInvocation"] | components["schemas"]["StepParamEasingInvocation"] | components["schemas"]["IntegerMathInvocation"] | components["schemas"]["BlankImageInvocation"] | components["schemas"]["IPAdapterInvocation"] | components["schemas"]["CoreMetadataInvocation"] | components["schemas"]["ConditioningCollectionInvocation"] | components["schemas"]["ZoeDepthImageProcessorInvocation"] | components["schemas"]["LatentsToImageInvocation"] | components["schemas"]["ImageMultiplyInvocation"] | components["schemas"]["LinearUIOutputInvocation"] | components["schemas"]["CannyImageProcessorInvocation"] | components["schemas"]["MetadataInvocation"] | components["schemas"]["FaceIdentifierInvocation"] | components["schemas"]["ImagePasteInvocation"] | components["schemas"]["BooleanInvocation"] | components["schemas"]["FloatCollectionInvocation"] | components["schemas"]["HedImageProcessorInvocation"] | components["schemas"]["PromptsFromFileInvocation"] | components["schemas"]["MlsdImageProcessorInvocation"] | components["schemas"]["RandomRangeInvocation"] | components["schemas"]["StringInvocation"] | components["schemas"]["SchedulerInvocation"] | components["schemas"]["StringCollectionInvocation"] | components["schemas"]["GraphInvocation"] | components["schemas"]["DenoiseLatentsInvocation"] | components["schemas"]["MergeMetadataInvocation"] | components["schemas"]["ImageCropInvocation"] | components["schemas"]["SDXLCompelPromptInvocation"] | components["schemas"]["ImageCollectionInvocation"] | components["schemas"]["ONNXPromptInvocation"] | components["schemas"]["InfillColorInvocation"] | components["schemas"]["BooleanCollectionInvocation"] | components["schemas"]["MaskCombineInvocation"] | components["schemas"]["MetadataItemInvocation"] | components["schemas"]["ShowImageInvocation"] | components["schemas"]["ESRGANInvocation"] | components["schemas"]["ImageConvertInvocation"] | components["schemas"]["PidiImageProcessorInvocation"] | components["schemas"]["IntegerInvocation"] | components["schemas"]["ONNXTextToLatentsInvocation"] | components["schemas"]["StringJoinInvocation"] | components["schemas"]["ImageLerpInvocation"] | components["schemas"]["RangeInvocation"]; }; /** * Edges @@ -3257,7 +3257,7 @@ export type components = { * @description The results of node executions */ results: { - [key: string]: components["schemas"]["SeamlessModeOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["String2Output"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["VAEOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["SchedulerOutput"]; + [key: string]: components["schemas"]["LatentsCollectionOutput"] | components["schemas"]["MetadataOutput"] | components["schemas"]["ImageOutput"] | components["schemas"]["StringPosNegOutput"] | components["schemas"]["MetadataItemOutput"] | components["schemas"]["SDXLLoraLoaderOutput"] | components["schemas"]["UNetOutput"] | components["schemas"]["FaceOffOutput"] | components["schemas"]["SeamlessModeOutput"] | components["schemas"]["CollectInvocationOutput"] | components["schemas"]["CLIPOutput"] | components["schemas"]["StringOutput"] | components["schemas"]["StringCollectionOutput"] | components["schemas"]["IntegerOutput"] | components["schemas"]["IntegerCollectionOutput"] | components["schemas"]["LatentsOutput"] | components["schemas"]["FloatCollectionOutput"] | components["schemas"]["BooleanCollectionOutput"] | components["schemas"]["IPAdapterOutput"] | components["schemas"]["String2Output"] | components["schemas"]["VAEOutput"] | components["schemas"]["NoiseOutput"] | components["schemas"]["SDXLRefinerModelLoaderOutput"] | components["schemas"]["ConditioningCollectionOutput"] | components["schemas"]["LoraLoaderOutput"] | components["schemas"]["BooleanOutput"] | components["schemas"]["FloatOutput"] | components["schemas"]["DenoiseMaskOutput"] | components["schemas"]["ClipSkipInvocationOutput"] | components["schemas"]["T2IAdapterOutput"] | components["schemas"]["ColorCollectionOutput"] | components["schemas"]["ConditioningOutput"] | components["schemas"]["ONNXModelLoaderOutput"] | components["schemas"]["GraphInvocationOutput"] | components["schemas"]["FaceMaskOutput"] | components["schemas"]["ControlOutput"] | components["schemas"]["ColorOutput"] | components["schemas"]["ModelLoaderOutput"] | components["schemas"]["ImageCollectionOutput"] | components["schemas"]["SDXLModelLoaderOutput"] | components["schemas"]["IterateInvocationOutput"] | components["schemas"]["SchedulerOutput"]; }; /** * Errors @@ -9657,11 +9657,11 @@ export type components = { */ version: string; /** - * Is Custom + * Node Pack * @description Whether or not this is a custom node - * @default false + * @default null */ - is_custom: boolean; + node_pack: string | null; }; /** * UIType @@ -9691,54 +9691,54 @@ export type components = { * @enum {string} */ UIType: "SDXLMainModelField" | "SDXLRefinerModelField" | "ONNXModelField" | "VAEModelField" | "LoRAModelField" | "ControlNetModelField" | "IPAdapterModelField" | "SchedulerField" | "AnyField" | "CollectionField" | "CollectionItemField" | "DEPRECATED_Boolean" | "DEPRECATED_Color" | "DEPRECATED_Conditioning" | "DEPRECATED_Control" | "DEPRECATED_Float" | "DEPRECATED_Image" | "DEPRECATED_Integer" | "DEPRECATED_Latents" | "DEPRECATED_String" | "DEPRECATED_BooleanCollection" | "DEPRECATED_ColorCollection" | "DEPRECATED_ConditioningCollection" | "DEPRECATED_ControlCollection" | "DEPRECATED_FloatCollection" | "DEPRECATED_ImageCollection" | "DEPRECATED_IntegerCollection" | "DEPRECATED_LatentsCollection" | "DEPRECATED_StringCollection" | "DEPRECATED_BooleanPolymorphic" | "DEPRECATED_ColorPolymorphic" | "DEPRECATED_ConditioningPolymorphic" | "DEPRECATED_ControlPolymorphic" | "DEPRECATED_FloatPolymorphic" | "DEPRECATED_ImagePolymorphic" | "DEPRECATED_IntegerPolymorphic" | "DEPRECATED_LatentsPolymorphic" | "DEPRECATED_StringPolymorphic" | "DEPRECATED_MainModel" | "DEPRECATED_UNet" | "DEPRECATED_Vae" | "DEPRECATED_CLIP" | "DEPRECATED_Collection" | "DEPRECATED_CollectionItem" | "DEPRECATED_Enum" | "DEPRECATED_WorkflowField" | "DEPRECATED_IsIntermediate" | "DEPRECATED_BoardField" | "DEPRECATED_MetadataItem" | "DEPRECATED_MetadataItemCollection" | "DEPRECATED_MetadataItemPolymorphic" | "DEPRECATED_MetadataDict"; - /** - * T2IAdapterModelFormat - * @description An enumeration. - * @enum {string} - */ - T2IAdapterModelFormat: "diffusers"; /** * StableDiffusionXLModelFormat * @description An enumeration. * @enum {string} */ StableDiffusionXLModelFormat: "checkpoint" | "diffusers"; - /** - * StableDiffusion2ModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; - /** - * StableDiffusionOnnxModelFormat - * @description An enumeration. - * @enum {string} - */ - StableDiffusionOnnxModelFormat: "olive" | "onnx"; - /** - * ControlNetModelFormat - * @description An enumeration. - * @enum {string} - */ - ControlNetModelFormat: "checkpoint" | "diffusers"; - /** - * CLIPVisionModelFormat - * @description An enumeration. - * @enum {string} - */ - CLIPVisionModelFormat: "diffusers"; /** * StableDiffusion1ModelFormat * @description An enumeration. * @enum {string} */ StableDiffusion1ModelFormat: "checkpoint" | "diffusers"; + /** + * CLIPVisionModelFormat + * @description An enumeration. + * @enum {string} + */ + CLIPVisionModelFormat: "diffusers"; + /** + * T2IAdapterModelFormat + * @description An enumeration. + * @enum {string} + */ + T2IAdapterModelFormat: "diffusers"; + /** + * ControlNetModelFormat + * @description An enumeration. + * @enum {string} + */ + ControlNetModelFormat: "checkpoint" | "diffusers"; /** * IPAdapterModelFormat * @description An enumeration. * @enum {string} */ IPAdapterModelFormat: "invokeai"; + /** + * StableDiffusionOnnxModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusionOnnxModelFormat: "olive" | "onnx"; + /** + * StableDiffusion2ModelFormat + * @description An enumeration. + * @enum {string} + */ + StableDiffusion2ModelFormat: "checkpoint" | "diffusers"; }; responses: never; parameters: never;