mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-27 16:33:49 +00:00
perf: flow value type
This commit is contained in:
@@ -4,7 +4,8 @@ import {
|
||||
FlowModuleTypeEnum,
|
||||
FlowInputItemTypeEnum,
|
||||
FlowOutputItemTypeEnum,
|
||||
SpecialInputKeyEnum
|
||||
SpecialInputKeyEnum,
|
||||
FlowValueTypeEnum
|
||||
} from './index';
|
||||
import type { AppItemType } from '@/types/app';
|
||||
import type { FlowModuleTemplateType } from '@/types/flow';
|
||||
@@ -56,7 +57,7 @@ export const UserGuideModule: FlowModuleTemplateType = {
|
||||
};
|
||||
export const UserInputModule: FlowModuleTemplateType = {
|
||||
logo: '/imgs/module/userChatInput.png',
|
||||
name: '用户问题',
|
||||
name: '用户问题(对话入口)',
|
||||
intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
|
||||
flowType: FlowModuleTypeEnum.questionInput,
|
||||
url: '/app/modules/init/userChatInput',
|
||||
@@ -72,6 +73,7 @@ export const UserInputModule: FlowModuleTemplateType = {
|
||||
key: SystemInputEnum.userChatInput,
|
||||
label: '用户问题',
|
||||
type: FlowOutputItemTypeEnum.source,
|
||||
valueType: FlowValueTypeEnum.string,
|
||||
targets: []
|
||||
}
|
||||
]
|
||||
@@ -101,6 +103,7 @@ export const HistoryModule: FlowModuleTemplateType = {
|
||||
{
|
||||
key: SystemInputEnum.history,
|
||||
label: '聊天记录',
|
||||
valueType: FlowValueTypeEnum.chatHistory,
|
||||
type: FlowOutputItemTypeEnum.source,
|
||||
targets: []
|
||||
}
|
||||
@@ -155,6 +158,7 @@ export const ChatModule: FlowModuleTemplateType = {
|
||||
key: 'systemPrompt',
|
||||
type: FlowInputItemTypeEnum.textarea,
|
||||
label: '系统提示词',
|
||||
valueType: FlowValueTypeEnum.string,
|
||||
description: ChatModelSystemTip,
|
||||
placeholder: ChatModelSystemTip,
|
||||
value: ''
|
||||
@@ -162,6 +166,7 @@ export const ChatModule: FlowModuleTemplateType = {
|
||||
{
|
||||
key: 'limitPrompt',
|
||||
type: FlowInputItemTypeEnum.textarea,
|
||||
valueType: FlowValueTypeEnum.string,
|
||||
label: '限定词',
|
||||
description: ChatModelLimitTip,
|
||||
placeholder: ChatModelLimitTip,
|
||||
@@ -171,7 +176,8 @@ export const ChatModule: FlowModuleTemplateType = {
|
||||
{
|
||||
key: 'quoteQA',
|
||||
type: FlowInputItemTypeEnum.target,
|
||||
label: '引用内容'
|
||||
label: '引用内容',
|
||||
valueType: FlowValueTypeEnum.kbQuote
|
||||
},
|
||||
Input_Template_History,
|
||||
Input_Template_UserChatInput
|
||||
@@ -183,6 +189,14 @@ export const ChatModule: FlowModuleTemplateType = {
|
||||
description: '直接响应,无需配置',
|
||||
type: FlowOutputItemTypeEnum.hidden,
|
||||
targets: []
|
||||
},
|
||||
{
|
||||
key: 'finish',
|
||||
label: '回复结束',
|
||||
description: 'AI 回复完成后触发',
|
||||
valueType: FlowValueTypeEnum.boolean,
|
||||
type: FlowOutputItemTypeEnum.source,
|
||||
targets: []
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -236,12 +250,14 @@ export const KBSearchModule: FlowModuleTemplateType = {
|
||||
key: 'isEmpty',
|
||||
label: '搜索结果为空',
|
||||
type: FlowOutputItemTypeEnum.source,
|
||||
valueType: FlowValueTypeEnum.boolean,
|
||||
targets: []
|
||||
},
|
||||
{
|
||||
key: 'unEmpty',
|
||||
label: '搜索结果不为空',
|
||||
type: FlowOutputItemTypeEnum.source,
|
||||
valueType: FlowValueTypeEnum.boolean,
|
||||
targets: []
|
||||
},
|
||||
{
|
||||
@@ -249,6 +265,7 @@ export const KBSearchModule: FlowModuleTemplateType = {
|
||||
label: '引用内容',
|
||||
description: '搜索结果为空时不返回',
|
||||
type: FlowOutputItemTypeEnum.source,
|
||||
valueType: FlowValueTypeEnum.kbQuote,
|
||||
targets: []
|
||||
}
|
||||
]
|
||||
@@ -257,7 +274,8 @@ export const KBSearchModule: FlowModuleTemplateType = {
|
||||
export const AnswerModule: FlowModuleTemplateType = {
|
||||
logo: '/imgs/module/reply.png',
|
||||
name: '指定回复',
|
||||
intro: '该模块可以直接回复一段指定的内容。常用于引导、提示。',
|
||||
intro: '该模块可以直接回复一段指定的内容。常用于引导、提示',
|
||||
description: '该模块可以直接回复一段指定的内容。常用于引导、提示',
|
||||
flowType: FlowModuleTypeEnum.answerNode,
|
||||
inputs: [
|
||||
Input_Template_TFSwitch,
|
||||
@@ -265,7 +283,8 @@ export const AnswerModule: FlowModuleTemplateType = {
|
||||
key: SpecialInputKeyEnum.answerText,
|
||||
value: '',
|
||||
type: FlowInputItemTypeEnum.textarea,
|
||||
label: '回复的内容'
|
||||
label: '回复的内容',
|
||||
description: '可以使用 \\n 来实现换行'
|
||||
}
|
||||
],
|
||||
outputs: []
|
||||
@@ -309,6 +328,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
|
||||
{
|
||||
key: 'systemPrompt',
|
||||
type: FlowInputItemTypeEnum.textarea,
|
||||
valueType: FlowValueTypeEnum.string,
|
||||
label: '系统提示词',
|
||||
description:
|
||||
'你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。',
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import type { BoxProps } from '@chakra-ui/react';
|
||||
|
||||
export enum FlowInputItemTypeEnum {
|
||||
systemInput = 'systemInput', // history, userChatInput, variableInput
|
||||
input = 'input',
|
||||
@@ -35,6 +37,36 @@ export enum SpecialInputKeyEnum {
|
||||
'answerText' = 'text'
|
||||
}
|
||||
|
||||
export enum FlowValueTypeEnum {
|
||||
'string' = 'string',
|
||||
'number' = 'number',
|
||||
'boolean' = 'boolean',
|
||||
'chatHistory' = 'chatHistory',
|
||||
'kbQuote' = 'kbQuote',
|
||||
'other' = 'other'
|
||||
}
|
||||
|
||||
export const FlowValueTypeStyle: Record<`${FlowValueTypeEnum}`, BoxProps> = {
|
||||
[FlowValueTypeEnum.string]: {
|
||||
background: '#36ADEF'
|
||||
},
|
||||
[FlowValueTypeEnum.number]: {
|
||||
background: '#FB7C3C'
|
||||
},
|
||||
[FlowValueTypeEnum.boolean]: {
|
||||
background: '#E7D118'
|
||||
},
|
||||
[FlowValueTypeEnum.chatHistory]: {
|
||||
background: '#00A9A6'
|
||||
},
|
||||
[FlowValueTypeEnum.kbQuote]: {
|
||||
background: '#A558C9'
|
||||
},
|
||||
[FlowValueTypeEnum.other]: {
|
||||
background: '#9CA2A8'
|
||||
}
|
||||
};
|
||||
|
||||
export const initModuleType: Record<string, boolean> = {
|
||||
[FlowModuleTypeEnum.historyNode]: true,
|
||||
[FlowModuleTypeEnum.questionInput]: true
|
||||
|
@@ -1,22 +1,25 @@
|
||||
import { FlowInputItemType } from '@/types/flow';
|
||||
import { SystemInputEnum } from '../app';
|
||||
import { FlowInputItemTypeEnum } from './index';
|
||||
import { FlowInputItemTypeEnum, FlowValueTypeEnum } from './index';
|
||||
|
||||
export const Input_Template_TFSwitch: FlowInputItemType = {
|
||||
key: SystemInputEnum.switch,
|
||||
type: FlowInputItemTypeEnum.target,
|
||||
label: '触发器'
|
||||
label: '触发器',
|
||||
valueType: FlowValueTypeEnum.boolean
|
||||
};
|
||||
|
||||
export const Input_Template_History: FlowInputItemType = {
|
||||
key: SystemInputEnum.history,
|
||||
type: FlowInputItemTypeEnum.target,
|
||||
label: '聊天记录'
|
||||
label: '聊天记录',
|
||||
valueType: FlowValueTypeEnum.chatHistory
|
||||
};
|
||||
|
||||
export const Input_Template_UserChatInput: FlowInputItemType = {
|
||||
key: SystemInputEnum.userChatInput,
|
||||
type: FlowInputItemTypeEnum.target,
|
||||
label: '用户问题',
|
||||
required: true
|
||||
required: true,
|
||||
valueType: FlowValueTypeEnum.string
|
||||
};
|
||||
|
@@ -3,7 +3,6 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { authUser } from '@/service/utils/auth';
|
||||
import { connectToDatabase, App } from '@/service/mongo';
|
||||
import { EditFormType } from '@/utils/app';
|
||||
import { AppModuleInputItemType } from '@/types/app';
|
||||
import { FlowModuleTypeEnum, SpecialInputKeyEnum } from '@/constants/flow';
|
||||
import { TaskResponseKeyEnum } from '@/constants/chat';
|
||||
|
@@ -11,7 +11,8 @@ import { Handle, Position } from 'reactflow';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 4);
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { FlowOutputItemTypeEnum } from '@/constants/flow';
|
||||
import { FlowOutputItemTypeEnum, FlowValueTypeEnum } from '@/constants/flow';
|
||||
import SourceHandle from '../render/SourceHandle';
|
||||
|
||||
const NodeCQNode = ({
|
||||
data: { moduleId, inputs, outputs, onChangeNode, ...props }
|
||||
@@ -82,19 +83,7 @@ const NodeCQNode = ({
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Handle
|
||||
style={{
|
||||
top: '50%',
|
||||
right: '-14px',
|
||||
transform: 'translate(50%,-50%)',
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
background: '#9CA2A8'
|
||||
}}
|
||||
type="source"
|
||||
id={item.key}
|
||||
position={Position.Right}
|
||||
/>
|
||||
<SourceHandle handleKey={item.key} valueType={FlowValueTypeEnum.boolean} />
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
|
@@ -1,31 +1,26 @@
|
||||
import React from 'react';
|
||||
import { Handle, Position, NodeProps } from 'reactflow';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import NodeCard from '../modules/NodeCard';
|
||||
import { FlowModuleItemType } from '@/types/flow';
|
||||
import Container from '../modules/Container';
|
||||
import { SystemInputEnum } from '@/constants/app';
|
||||
import { FlowValueTypeEnum } from '@/constants/flow';
|
||||
import SourceHandle from '../render/SourceHandle';
|
||||
|
||||
const QuestionInputNode = ({
|
||||
data: { inputs, outputs, onChangeNode, ...props }
|
||||
}: NodeProps<FlowModuleItemType>) => {
|
||||
return (
|
||||
<NodeCard minW={'220px'} {...props}>
|
||||
<NodeCard minW={'240px'} {...props}>
|
||||
<Container borderTop={'2px solid'} borderTopColor={'myGray.200'} textAlign={'end'}>
|
||||
<Box>用户问题</Box>
|
||||
<Handle
|
||||
style={{
|
||||
bottom: '0',
|
||||
right: '0',
|
||||
transform: 'translate(50%,-5px)',
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
background: '#9CA2A8'
|
||||
}}
|
||||
id={SystemInputEnum.userChatInput}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
/>
|
||||
<Box position={'relative'}>
|
||||
用户问题
|
||||
<SourceHandle
|
||||
handleKey={SystemInputEnum.userChatInput}
|
||||
valueType={FlowValueTypeEnum.string}
|
||||
/>
|
||||
</Box>
|
||||
</Container>
|
||||
</NodeCard>
|
||||
);
|
||||
|
@@ -37,7 +37,11 @@ const NodeCard = ({
|
||||
</Box>
|
||||
{description && (
|
||||
<MyTooltip label={description} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
<QuestionOutlineIcon
|
||||
display={['none', 'inline']}
|
||||
transform={'translateY(-1px)'}
|
||||
ml={1}
|
||||
/>
|
||||
</MyTooltip>
|
||||
)}
|
||||
<Box flex={1} />
|
||||
|
@@ -12,10 +12,10 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { FlowInputItemTypeEnum } from '@/constants/flow';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { Handle, Position } from 'reactflow';
|
||||
import MySelect from '@/components/Select';
|
||||
import MySlider from '@/components/Slider';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import TargetHandle from './TargetHandle';
|
||||
|
||||
export const Label = ({
|
||||
required = false,
|
||||
@@ -35,7 +35,7 @@ export const Label = ({
|
||||
)}
|
||||
{description && (
|
||||
<MyTooltip label={description} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} ml={1} />
|
||||
<QuestionOutlineIcon display={['none', 'inline']} transform={'translateY(-1px)'} ml={1} />
|
||||
</MyTooltip>
|
||||
)}
|
||||
</Box>
|
||||
@@ -61,6 +61,10 @@ const RenderBody = ({
|
||||
{!!item.label && (
|
||||
<Label required={item.required} description={item.description}>
|
||||
{item.label}
|
||||
|
||||
{(item.type === FlowInputItemTypeEnum.target || item.valueType) && (
|
||||
<TargetHandle handleKey={item.key} valueType={item.valueType} />
|
||||
)}
|
||||
</Label>
|
||||
)}
|
||||
<Box mt={2} className={'nodrag'}>
|
||||
@@ -148,22 +152,6 @@ const RenderBody = ({
|
||||
{item.type === FlowInputItemTypeEnum.custom && CustomComponent[item.key] && (
|
||||
<>{CustomComponent[item.key]({ ...item })}</>
|
||||
)}
|
||||
{item.type === FlowInputItemTypeEnum.target && (
|
||||
<Handle
|
||||
style={{
|
||||
top: '50%',
|
||||
left: '-14px',
|
||||
transform: 'translate(-50%,-50%)',
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
background: '#9CA2A8'
|
||||
}}
|
||||
id={item.key}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
onConnect={(params) => console.log('handle onConnect', params)}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
|
@@ -5,6 +5,7 @@ import { FlowOutputItemTypeEnum } from '@/constants/flow';
|
||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||
import { Handle, Position } from 'reactflow';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
import SourceHandle from './SourceHandle';
|
||||
|
||||
const Label = ({
|
||||
children,
|
||||
@@ -16,7 +17,7 @@ const Label = ({
|
||||
<Flex as={'label'} justifyContent={'right'} alignItems={'center'} position={'relative'}>
|
||||
{description && (
|
||||
<MyTooltip label={description} forceShow>
|
||||
<QuestionOutlineIcon display={['none', 'inline']} mr={1} />
|
||||
<QuestionOutlineIcon display={['none', 'inline']} transform={'translateY(-1px)'} mr={1} />
|
||||
</MyTooltip>
|
||||
)}
|
||||
{children}
|
||||
@@ -33,19 +34,7 @@ const RenderBody = ({ flowOutputList }: { flowOutputList: FlowOutputItemType[] }
|
||||
<Label description={item.description}>{item.label}</Label>
|
||||
<Box mt={FlowOutputItemTypeEnum.answer ? 0 : 2} className={'nodrag'}>
|
||||
{item.type === FlowOutputItemTypeEnum.source && (
|
||||
<Handle
|
||||
style={{
|
||||
top: '50%',
|
||||
right: '-14px',
|
||||
transform: 'translate(50%,-50%)',
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
background: '#9CA2A8'
|
||||
}}
|
||||
type="source"
|
||||
id={item.key}
|
||||
position={Position.Right}
|
||||
/>
|
||||
<SourceHandle handleKey={item.key} valueType={item.valueType} />
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
@@ -0,0 +1,42 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, BoxProps } from '@chakra-ui/react';
|
||||
import { Handle, Position } from 'reactflow';
|
||||
import { FlowValueTypeEnum, FlowValueTypeStyle } from '@/constants/flow';
|
||||
|
||||
interface Props extends BoxProps {
|
||||
handleKey: string;
|
||||
valueType?: `${FlowValueTypeEnum}`;
|
||||
}
|
||||
|
||||
const SourceHandle = ({ handleKey, valueType, ...props }: Props) => {
|
||||
const valueStyle = useMemo(
|
||||
() =>
|
||||
valueType
|
||||
? FlowValueTypeStyle[valueType]
|
||||
: (FlowValueTypeStyle[FlowValueTypeEnum.other] as any),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<Box
|
||||
position={'absolute'}
|
||||
top={'50%'}
|
||||
right={'-16px'}
|
||||
transform={'translate(50%,-50%)'}
|
||||
{...props}
|
||||
>
|
||||
<Handle
|
||||
style={{
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
...valueStyle
|
||||
}}
|
||||
type="source"
|
||||
id={handleKey}
|
||||
position={Position.Right}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SourceHandle;
|
@@ -0,0 +1,44 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { Box, BoxProps } from '@chakra-ui/react';
|
||||
import { Handle, OnConnect, Position } from 'reactflow';
|
||||
import { FlowValueTypeEnum, FlowValueTypeStyle } from '@/constants/flow';
|
||||
|
||||
interface Props extends BoxProps {
|
||||
handleKey: string;
|
||||
valueType?: `${FlowValueTypeEnum}`;
|
||||
onConnect?: OnConnect;
|
||||
}
|
||||
|
||||
const TargetHandle = ({ handleKey, valueType, onConnect, ...props }: Props) => {
|
||||
const valueStyle = useMemo(
|
||||
() =>
|
||||
valueType
|
||||
? FlowValueTypeStyle[valueType]
|
||||
: (FlowValueTypeStyle[FlowValueTypeEnum.other] as any),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<Box
|
||||
position={'absolute'}
|
||||
top={'50%'}
|
||||
left={'-16px'}
|
||||
transform={'translate(50%,-50%)'}
|
||||
{...props}
|
||||
>
|
||||
<Handle
|
||||
style={{
|
||||
width: '12px',
|
||||
height: '12px',
|
||||
...valueStyle
|
||||
}}
|
||||
type="target"
|
||||
id={handleKey}
|
||||
datatype={valueStyle}
|
||||
position={Position.Left}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default TargetHandle;
|
@@ -30,6 +30,7 @@ export type ChatProps = {
|
||||
export type ChatResponse = {
|
||||
[TaskResponseKeyEnum.answerText]: string;
|
||||
[TaskResponseKeyEnum.responseData]: ChatHistoryItemResType;
|
||||
finish: boolean;
|
||||
};
|
||||
|
||||
/* request openai chat */
|
||||
@@ -143,7 +144,8 @@ export const dispatchChatCompletion = async (props: Record<string, any>): Promis
|
||||
maxToken,
|
||||
quoteList: filterQuoteQA,
|
||||
completeMessages
|
||||
}
|
||||
},
|
||||
finish: true
|
||||
};
|
||||
};
|
||||
|
||||
|
5
client/src/types/flow.d.ts
vendored
5
client/src/types/flow.d.ts
vendored
@@ -1,7 +1,8 @@
|
||||
import {
|
||||
FlowBodyItemTypeEnum,
|
||||
FlowInputItemTypeEnum,
|
||||
FlowOutputItemTypeEnum
|
||||
FlowOutputItemTypeEnum,
|
||||
FlowValueTypeEnum
|
||||
} from '@/constants/flow';
|
||||
import { Connection } from 'reactflow';
|
||||
import type { AppModuleItemType } from './app';
|
||||
@@ -18,6 +19,7 @@ export type FlowModuleItemChangeProps = {
|
||||
export type FlowInputItemType = {
|
||||
key: string; // 字段名
|
||||
value?: any;
|
||||
valueType?: `${FlowValueTypeEnum}`;
|
||||
type: `${FlowInputItemTypeEnum}`;
|
||||
label: string;
|
||||
connected?: boolean;
|
||||
@@ -39,6 +41,7 @@ export type FlowOutputItemType = {
|
||||
key: string; // 字段名
|
||||
label: string;
|
||||
description?: string;
|
||||
valueType?: `${FlowValueTypeEnum}`;
|
||||
type: `${FlowOutputItemTypeEnum}`;
|
||||
targets: FlowOutputTargetItemType[];
|
||||
};
|
||||
|
@@ -76,10 +76,7 @@ export const appModule2FlowNode = ({
|
||||
// replace item data
|
||||
const moduleItem: FlowModuleItemType = {
|
||||
...item,
|
||||
logo: template.logo,
|
||||
name: template.name,
|
||||
intro: template.intro,
|
||||
url: template.url,
|
||||
...template,
|
||||
inputs: template.inputs.map((templateInput) => {
|
||||
// use latest inputs
|
||||
const itemInput = item.inputs.find((item) => item.key === templateInput.key) || templateInput;
|
||||
|
Reference in New Issue
Block a user