feat(ui): support string batches

This commit is contained in:
psychedelicious
2025-01-10 10:32:23 +10:00
parent e077fe8046
commit b52b271dc4
9 changed files with 365 additions and 7 deletions

View File

@@ -1,5 +1,6 @@
import { logger } from 'app/logging/logger';
import type { NodesState } from 'features/nodes/store/types';
import type { InvocationNode } from 'features/nodes/types/invocation';
import { isInvocationNode } from 'features/nodes/types/invocation';
import { omit, reduce } from 'lodash-es';
import type { AnyInvocation, Graph } from 'services/api/types';
@@ -7,6 +8,17 @@ import { v4 as uuidv4 } from 'uuid';
const log = logger('workflows');
// These nodes are not executable, they exist for the frontend only
const filterNonExecutableNodes = (node: InvocationNode) => {
if (node.data.type === 'image_batch') {
return false;
}
if (node.data.type === 'string_batch') {
return false;
}
return true;
};
/**
* Builds a graph from the node editor state.
*/
@@ -14,7 +26,7 @@ export const buildNodesGraph = (nodesState: NodesState): Graph => {
const { nodes, edges } = nodesState;
// Exclude all batch nodes - we will handle these in the batch setup in a diff function
const filteredNodes = nodes.filter(isInvocationNode).filter((node) => node.data.type !== 'image_batch');
const filteredNodes = nodes.filter(isInvocationNode).filter(filterNonExecutableNodes);
// Reduce the node editor nodes into invocation graph nodes
const parsedNodes = filteredNodes.reduce<NonNullable<Graph['nodes']>>((nodesAccumulator, node) => {

View File

@@ -28,12 +28,17 @@ import type {
SpandrelImageToImageModelFieldInputTemplate,
StatefulFieldType,
StatelessFieldInputTemplate,
StringFieldCollectionInputTemplate,
StringFieldInputTemplate,
T2IAdapterModelFieldInputTemplate,
T5EncoderModelFieldInputTemplate,
VAEModelFieldInputTemplate,
} from 'features/nodes/types/field';
import { isImageCollectionFieldType, isStatefulFieldType } from 'features/nodes/types/field';
import {
isImageCollectionFieldType,
isStatefulFieldType,
isStringCollectionFieldType,
} from 'features/nodes/types/field';
import type { InvocationFieldSchema } from 'features/nodes/types/openapi';
import { isSchemaObject } from 'features/nodes/types/openapi';
import { t } from 'i18next';
@@ -133,6 +138,36 @@ const buildStringFieldInputTemplate: FieldInputTemplateBuilder<StringFieldInputT
return template;
};
const buildStringFieldCollectionInputTemplate: FieldInputTemplateBuilder<StringFieldCollectionInputTemplate> = ({
schemaObject,
baseField,
fieldType,
}) => {
const template: StringFieldCollectionInputTemplate = {
...baseField,
type: fieldType,
default: schemaObject.default ?? (schemaObject.orig_required ? [] : undefined),
};
if (schemaObject.minLength !== undefined) {
template.minLength = schemaObject.minLength;
}
if (schemaObject.maxLength !== undefined) {
template.maxLength = schemaObject.maxLength;
}
if (schemaObject.minItems !== undefined) {
template.minItems = schemaObject.minItems;
}
if (schemaObject.maxItems !== undefined) {
template.maxItems = schemaObject.maxItems;
}
return template;
};
const buildBooleanFieldInputTemplate: FieldInputTemplateBuilder<BooleanFieldInputTemplate> = ({
schemaObject,
baseField,
@@ -569,12 +604,17 @@ export const buildFieldInputTemplate = (
if (isStatefulFieldType(fieldType)) {
if (isImageCollectionFieldType(fieldType)) {
fieldType;
return buildImageFieldCollectionInputTemplate({
schemaObject: fieldSchema,
baseField,
fieldType,
});
} else if (isStringCollectionFieldType(fieldType)) {
return buildStringFieldCollectionInputTemplate({
schemaObject: fieldSchema,
baseField,
fieldType,
});
} else {
const builder = TEMPLATE_BUILDER_MAP[fieldType.name];
const template = builder({