feat: add form input node (#2773)

* add node

* dispatch

* extract InputTypeConfig component

* question tip

* fix build

* fix

* fix
This commit is contained in:
heheer
2024-09-26 13:48:03 +08:00
committed by GitHub
parent edebfdf5ef
commit 1cf76ee7df
34 changed files with 1326 additions and 419 deletions

View File

@@ -9,8 +9,7 @@ import type {
ChatCompletionUserMessageParam as SdkChatCompletionUserMessageParam
} from 'openai/resources';
import { ChatMessageTypeEnum } from './constants';
import { InteractiveNodeResponseItemType } from '../workflow/template/system/userSelect/type';
import { InteractiveNodeResponseItemType } from '../workflow/template/system/interactive/type';
export * from 'openai/resources';
// Extension of ChatCompletionMessageParam, Add file url type

View File

@@ -15,7 +15,7 @@ import type { AppSchema as AppType } from '@fastgpt/global/core/app/type.d';
import { DatasetSearchModeEnum } from '../dataset/constants';
import { DispatchNodeResponseType } from '../workflow/runtime/type.d';
import { ChatBoxInputType } from '../../../../projects/app/src/components/core/chat/ChatContainer/ChatBox/type';
import { InteractiveNodeResponseItemType } from '../workflow/template/system/userSelect/type';
import { InteractiveNodeResponseItemType } from '../workflow/template/system/interactive/type';
export type ChatSchema = {
_id: string;

View File

@@ -148,7 +148,10 @@ export enum NodeInputKeyEnum {
// loop start
loopStartInput = 'loopStartInput',
// loop end
loopEndInput = 'loopEndInput'
loopEndInput = 'loopEndInput',
// form input
userInputForms = 'userInputForms'
}
export enum NodeOutputKeyEnum {
@@ -197,7 +200,10 @@ export enum NodeOutputKeyEnum {
loopArray = 'loopArray',
// loop start
loopStartInput = 'loopStartInput'
loopStartInput = 'loopStartInput',
// form input
formInputResult = 'formInputResult'
}
export enum VariableInputEnum {

View File

@@ -128,7 +128,8 @@ export enum FlowNodeTypeEnum {
userSelect = 'userSelect',
loop = 'loop',
loopStart = 'loopStart',
loopEnd = 'loopEnd'
loopEnd = 'loopEnd',
formInput = 'formInput'
}
// node IO value type

View File

@@ -182,6 +182,9 @@ export type DispatchNodeResponseType = {
loopInputValue?: any;
// loop end
loopOutputValue?: any;
// form input
formInputResult?: string;
};
export type DispatchNodeResultType<T = {}> = {

View File

@@ -54,6 +54,11 @@ export const getLastInteractiveValue = (histories: ChatItemType[]) => {
) {
return lastValue.interactive;
}
// Check is user input
if (lastValue.interactive.type === 'userInput' && !lastValue.interactive.params.submitted) {
return lastValue.interactive;
}
}
return null;

View File

@@ -28,10 +28,11 @@ import { CodeNode } from './system/sandbox';
import { TextEditorNode } from './system/textEditor';
import { CustomFeedbackNode } from './system/customFeedback';
import { ReadFilesNode } from './system/readFiles';
import { UserSelectNode } from './system/userSelect/index';
import { UserSelectNode } from './system/interactive/userSelect';
import { LoopNode } from './system/loop/loop';
import { LoopStartNode } from './system/loop/loopStart';
import { LoopEndNode } from './system/loop/loopEnd';
import { FormInputNode } from './system/interactive/formInput';
const systemNodes: FlowNodeTemplateType[] = [
AiChatModule,
@@ -58,7 +59,8 @@ export const appSystemModuleTemplates: FlowNodeTemplateType[] = [
WorkflowStart,
...systemNodes,
CustomFeedbackNode,
UserSelectNode
UserSelectNode,
FormInputNode
];
/* plugin flow module templates */
export const pluginSystemModuleTemplates: FlowNodeTemplateType[] = [

View File

@@ -0,0 +1,55 @@
import { i18nT } from '../../../../../../web/i18n/utils';
import {
FlowNodeTemplateTypeEnum,
NodeInputKeyEnum,
NodeOutputKeyEnum,
WorkflowIOValueTypeEnum
} from '../../../constants';
import {
FlowNodeInputTypeEnum,
FlowNodeOutputTypeEnum,
FlowNodeTypeEnum
} from '../../../node/constant';
import { FlowNodeTemplateType } from '../../../type/node';
import { getHandleConfig } from '../../utils';
export const FormInputNode: FlowNodeTemplateType = {
id: FlowNodeTypeEnum.formInput,
templateType: FlowNodeTemplateTypeEnum.interactive,
flowNodeType: FlowNodeTypeEnum.formInput,
sourceHandle: getHandleConfig(true, true, true, true),
targetHandle: getHandleConfig(true, true, true, true),
avatar: 'core/workflow/template/formInput',
name: i18nT('app:workflow.form_input'),
intro: i18nT(`app:workflow.form_input_tip`),
showStatus: true,
version: '4811',
inputs: [
{
key: NodeInputKeyEnum.description,
renderTypeList: [FlowNodeInputTypeEnum.textarea],
valueType: WorkflowIOValueTypeEnum.string,
label: i18nT('app:workflow.select_description'),
description: i18nT('app:workflow.input_description_tip'),
placeholder: i18nT('app:workflow.form_input_description_placeholder')
},
{
key: NodeInputKeyEnum.userInputForms,
renderTypeList: [FlowNodeInputTypeEnum.custom],
valueType: WorkflowIOValueTypeEnum.any,
label: '',
value: []
}
],
outputs: [
{
id: NodeOutputKeyEnum.formInputResult,
key: NodeOutputKeyEnum.formInputResult,
required: true,
label: i18nT('app:workflow.form_input_result'),
description: i18nT('app:workflow.form_input_result_tip'),
valueType: WorkflowIOValueTypeEnum.object,
type: FlowNodeOutputTypeEnum.static
}
]
};

View File

@@ -0,0 +1,56 @@
import { NodeOutputItemType } from '../../../../chat/type';
import { FlowNodeOutputItemType } from '../../../type/io';
import { RuntimeEdgeItemType } from '../../../runtime/type';
import { FlowNodeInputTypeEnum } from 'core/workflow/node/constant';
import { WorkflowIOValueTypeEnum } from 'core/workflow/constants';
export type UserSelectOptionItemType = {
key: string;
value: string;
};
export type UserInputFormItemType = {
type: FlowNodeInputTypeEnum;
key: string;
label: string;
value: any;
valueType: WorkflowIOValueTypeEnum;
description?: string;
defaultValue?: any;
required: boolean;
// input & textarea
maxLength?: number;
// numberInput
max?: number;
min?: number;
// select
list?: { label: string; value: string }[];
};
type InteractiveBasicType = {
entryNodeIds: string[];
memoryEdges: RuntimeEdgeItemType[];
nodeOutputs: NodeOutputItemType[];
};
type UserSelectInteractive = {
type: 'userSelect';
params: {
description: string;
userSelectOptions: UserSelectOptionItemType[];
userSelectedVal?: string;
};
};
type UserInputInteractive = {
type: 'userInput';
params: {
description: string;
inputForm: UserInputFormItemType[];
submitted?: boolean;
};
};
export type InteractiveNodeResponseItemType = InteractiveBasicType &
(UserSelectInteractive | UserInputInteractive);

View File

@@ -1,24 +0,0 @@
import { NodeOutputItemType } from '../../../../chat/type';
import { FlowNodeOutputItemType } from '../../../type/io';
import { RuntimeEdgeItemType } from '../../../runtime/type';
export type UserSelectOptionItemType = {
key: string;
value: string;
};
type InteractiveBasicType = {
entryNodeIds: string[];
memoryEdges: RuntimeEdgeItemType[];
nodeOutputs: NodeOutputItemType[];
};
type UserSelectInteractive = {
type: 'userSelect';
params: {
description: string;
userSelectOptions: UserSelectOptionItemType[];
userSelectedVal?: string;
};
};
export type InteractiveNodeResponseItemType = InteractiveBasicType & UserSelectInteractive;