mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 05:12:39 +00:00
569 lines
13 KiB
TypeScript
569 lines
13 KiB
TypeScript
import type { AppModuleItemType, VariableItemType } from '@/types/app';
|
|
import { chatModelList } from '@/store/static';
|
|
import {
|
|
FlowInputItemTypeEnum,
|
|
FlowModuleTypeEnum,
|
|
FlowValueTypeEnum,
|
|
SpecialInputKeyEnum
|
|
} from '@/constants/flow';
|
|
import { SystemInputEnum } from '@/constants/app';
|
|
import type { SelectedDatasetType } from '@/types/core/dataset';
|
|
import type { FlowInputItemType } from '@/types/core/app/flow';
|
|
import type { AIChatProps } from '@/types/core/aiChat';
|
|
import { getGuideModule, splitGuideModule } from '@/components/ChatBox/utils';
|
|
|
|
export type EditFormType = {
|
|
chatModel: AIChatProps;
|
|
kb: {
|
|
list: SelectedDatasetType;
|
|
searchSimilarity: number;
|
|
searchLimit: number;
|
|
searchEmptyText: string;
|
|
};
|
|
guide: {
|
|
welcome: {
|
|
text: string;
|
|
};
|
|
};
|
|
variables: VariableItemType[];
|
|
questionGuide: boolean;
|
|
};
|
|
export const getDefaultAppForm = (): EditFormType => {
|
|
const defaultChatModel = chatModelList[0];
|
|
|
|
return {
|
|
chatModel: {
|
|
model: defaultChatModel?.model,
|
|
systemPrompt: '',
|
|
temperature: 0,
|
|
quotePrompt: '',
|
|
quoteTemplate: '',
|
|
maxToken: defaultChatModel ? defaultChatModel.contextMaxToken / 2 : 4000,
|
|
frequency: 0.5,
|
|
presence: -0.5
|
|
},
|
|
kb: {
|
|
list: [],
|
|
searchSimilarity: 0.4,
|
|
searchLimit: 5,
|
|
searchEmptyText: ''
|
|
},
|
|
guide: {
|
|
welcome: {
|
|
text: ''
|
|
}
|
|
},
|
|
variables: [],
|
|
questionGuide: false
|
|
};
|
|
};
|
|
|
|
export const appModules2Form = (modules: AppModuleItemType[]) => {
|
|
const defaultAppForm = getDefaultAppForm();
|
|
const updateVal = ({
|
|
formKey,
|
|
inputs,
|
|
key
|
|
}: {
|
|
formKey: string;
|
|
inputs: FlowInputItemType[];
|
|
key: string;
|
|
}) => {
|
|
const propertyPath = formKey.split('.');
|
|
let currentObj: any = defaultAppForm;
|
|
for (let i = 0; i < propertyPath.length - 1; i++) {
|
|
currentObj = currentObj[propertyPath[i]];
|
|
}
|
|
|
|
const val =
|
|
inputs.find((item) => item.key === key)?.value ||
|
|
currentObj[propertyPath[propertyPath.length - 1]];
|
|
|
|
currentObj[propertyPath[propertyPath.length - 1]] = val;
|
|
};
|
|
|
|
modules.forEach((module) => {
|
|
if (module.flowType === FlowModuleTypeEnum.chatNode) {
|
|
updateVal({
|
|
formKey: 'chatModel.model',
|
|
inputs: module.inputs,
|
|
key: 'model'
|
|
});
|
|
updateVal({
|
|
formKey: 'chatModel.temperature',
|
|
inputs: module.inputs,
|
|
key: 'temperature'
|
|
});
|
|
updateVal({
|
|
formKey: 'chatModel.maxToken',
|
|
inputs: module.inputs,
|
|
key: 'maxToken'
|
|
});
|
|
updateVal({
|
|
formKey: 'chatModel.systemPrompt',
|
|
inputs: module.inputs,
|
|
key: 'systemPrompt'
|
|
});
|
|
updateVal({
|
|
formKey: 'chatModel.quoteTemplate',
|
|
inputs: module.inputs,
|
|
key: 'quoteTemplate'
|
|
});
|
|
updateVal({
|
|
formKey: 'chatModel.quotePrompt',
|
|
inputs: module.inputs,
|
|
key: 'quotePrompt'
|
|
});
|
|
} else if (module.flowType === FlowModuleTypeEnum.kbSearchNode) {
|
|
updateVal({
|
|
formKey: 'kb.list',
|
|
inputs: module.inputs,
|
|
key: 'kbList'
|
|
});
|
|
updateVal({
|
|
formKey: 'kb.searchSimilarity',
|
|
inputs: module.inputs,
|
|
key: 'similarity'
|
|
});
|
|
updateVal({
|
|
formKey: 'kb.searchLimit',
|
|
inputs: module.inputs,
|
|
key: 'limit'
|
|
});
|
|
// empty text
|
|
const emptyOutputs = module.outputs.find((item) => item.key === 'isEmpty')?.targets || [];
|
|
const emptyOutput = emptyOutputs[0];
|
|
if (emptyOutput) {
|
|
const target = modules.find((item) => item.moduleId === emptyOutput.moduleId);
|
|
defaultAppForm.kb.searchEmptyText =
|
|
target?.inputs?.find((item) => item.key === SpecialInputKeyEnum.answerText)?.value || '';
|
|
}
|
|
} else if (module.flowType === FlowModuleTypeEnum.userGuide) {
|
|
const { welcomeText, variableModules, questionGuide } = splitGuideModule(
|
|
getGuideModule(modules)
|
|
);
|
|
if (welcomeText) {
|
|
defaultAppForm.guide.welcome = {
|
|
text: welcomeText
|
|
};
|
|
}
|
|
|
|
defaultAppForm.variables = variableModules;
|
|
defaultAppForm.questionGuide = !!questionGuide;
|
|
}
|
|
});
|
|
|
|
return defaultAppForm;
|
|
};
|
|
|
|
const chatModelInput = (formData: EditFormType): FlowInputItemType[] => [
|
|
{
|
|
key: 'model',
|
|
value: formData.chatModel.model,
|
|
type: 'custom',
|
|
label: '对话模型',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'temperature',
|
|
value: formData.chatModel.temperature,
|
|
type: 'slider',
|
|
label: '温度',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'maxToken',
|
|
value: formData.chatModel.maxToken,
|
|
type: 'custom',
|
|
label: '回复上限',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'systemPrompt',
|
|
value: formData.chatModel.systemPrompt || '',
|
|
type: 'textarea',
|
|
label: '系统提示词',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'quoteTemplate',
|
|
value: formData.chatModel.quoteTemplate || '',
|
|
type: 'hidden',
|
|
label: '引用内容模板',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'quotePrompt',
|
|
value: formData.chatModel.quotePrompt || '',
|
|
type: 'hidden',
|
|
label: '引用内容提示词',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'switch',
|
|
type: 'target',
|
|
label: '触发器',
|
|
connected: formData.kb.list.length > 0
|
|
},
|
|
{
|
|
key: 'quoteQA',
|
|
type: 'target',
|
|
label: '引用内容',
|
|
connected: formData.kb.list.length > 0
|
|
},
|
|
{
|
|
key: 'history',
|
|
type: 'target',
|
|
label: '聊天记录',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'userChatInput',
|
|
type: 'target',
|
|
label: '用户问题',
|
|
connected: true
|
|
}
|
|
];
|
|
const userGuideTemplate = (formData: EditFormType): AppModuleItemType[] => [
|
|
{
|
|
name: '用户引导',
|
|
flowType: FlowModuleTypeEnum.userGuide,
|
|
inputs: [
|
|
{
|
|
key: SystemInputEnum.welcomeText,
|
|
type: FlowInputItemTypeEnum.hidden,
|
|
label: '开场白',
|
|
value: formData.guide.welcome.text
|
|
},
|
|
{
|
|
key: SystemInputEnum.variables,
|
|
type: FlowInputItemTypeEnum.hidden,
|
|
label: '对话框变量',
|
|
value: formData.variables
|
|
},
|
|
{
|
|
key: SystemInputEnum.questionGuide,
|
|
type: FlowInputItemTypeEnum.hidden,
|
|
label: '问题引导',
|
|
value: formData.questionGuide
|
|
}
|
|
],
|
|
outputs: [],
|
|
position: {
|
|
x: 447.98520778293346,
|
|
y: 721.4016845336229
|
|
},
|
|
moduleId: 'userGuide'
|
|
}
|
|
];
|
|
const simpleChatTemplate = (formData: EditFormType): AppModuleItemType[] => [
|
|
{
|
|
name: '用户问题(对话入口)',
|
|
flowType: FlowModuleTypeEnum.questionInput,
|
|
inputs: [
|
|
{
|
|
key: 'userChatInput',
|
|
connected: true,
|
|
label: '用户问题',
|
|
type: 'target'
|
|
}
|
|
],
|
|
outputs: [
|
|
{
|
|
key: 'userChatInput',
|
|
targets: [
|
|
{
|
|
moduleId: 'chatModule',
|
|
key: 'userChatInput'
|
|
}
|
|
]
|
|
}
|
|
],
|
|
position: {
|
|
x: 464.32198615344566,
|
|
y: 1602.2698463081606
|
|
},
|
|
moduleId: 'userChatInput'
|
|
},
|
|
{
|
|
name: '聊天记录',
|
|
flowType: FlowModuleTypeEnum.historyNode,
|
|
inputs: [
|
|
{
|
|
key: 'maxContext',
|
|
value: 6,
|
|
connected: true,
|
|
type: 'numberInput',
|
|
label: '最长记录数'
|
|
},
|
|
{
|
|
key: 'history',
|
|
type: 'hidden',
|
|
label: '聊天记录',
|
|
connected: true
|
|
}
|
|
],
|
|
outputs: [
|
|
{
|
|
key: 'history',
|
|
targets: [
|
|
{
|
|
moduleId: 'chatModule',
|
|
key: 'history'
|
|
}
|
|
]
|
|
}
|
|
],
|
|
position: {
|
|
x: 452.5466249541586,
|
|
y: 1276.3930310334215
|
|
},
|
|
moduleId: 'history'
|
|
},
|
|
{
|
|
name: 'AI 对话',
|
|
flowType: FlowModuleTypeEnum.chatNode,
|
|
inputs: chatModelInput(formData),
|
|
showStatus: true,
|
|
outputs: [
|
|
{
|
|
key: 'answerText',
|
|
label: '模型回复',
|
|
description: '直接响应,无需配置',
|
|
type: 'hidden',
|
|
targets: []
|
|
},
|
|
{
|
|
key: 'finish',
|
|
label: '回复结束',
|
|
description: 'AI 回复完成后触发',
|
|
valueType: 'boolean',
|
|
type: 'source',
|
|
targets: []
|
|
}
|
|
],
|
|
position: {
|
|
x: 981.9682828103937,
|
|
y: 890.014595014464
|
|
},
|
|
moduleId: 'chatModule'
|
|
}
|
|
];
|
|
const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [
|
|
{
|
|
name: '用户问题(对话入口)',
|
|
flowType: FlowModuleTypeEnum.questionInput,
|
|
inputs: [
|
|
{
|
|
key: 'userChatInput',
|
|
label: '用户问题',
|
|
type: 'target',
|
|
connected: true
|
|
}
|
|
],
|
|
outputs: [
|
|
{
|
|
key: 'userChatInput',
|
|
targets: [
|
|
{
|
|
moduleId: 'chatModule',
|
|
key: 'userChatInput'
|
|
},
|
|
{
|
|
moduleId: 'kbSearch',
|
|
key: 'userChatInput'
|
|
}
|
|
]
|
|
}
|
|
],
|
|
position: {
|
|
x: 464.32198615344566,
|
|
y: 1602.2698463081606
|
|
},
|
|
moduleId: 'userChatInput'
|
|
},
|
|
{
|
|
name: '聊天记录',
|
|
flowType: FlowModuleTypeEnum.historyNode,
|
|
inputs: [
|
|
{
|
|
key: 'maxContext',
|
|
value: 6,
|
|
connected: true,
|
|
type: 'numberInput',
|
|
label: '最长记录数'
|
|
},
|
|
{
|
|
key: 'history',
|
|
type: 'hidden',
|
|
label: '聊天记录',
|
|
connected: true
|
|
}
|
|
],
|
|
outputs: [
|
|
{
|
|
key: 'history',
|
|
targets: [
|
|
{
|
|
moduleId: 'chatModule',
|
|
key: 'history'
|
|
}
|
|
]
|
|
}
|
|
],
|
|
position: {
|
|
x: 452.5466249541586,
|
|
y: 1276.3930310334215
|
|
},
|
|
moduleId: 'history'
|
|
},
|
|
{
|
|
name: '知识库搜索',
|
|
flowType: FlowModuleTypeEnum.kbSearchNode,
|
|
showStatus: true,
|
|
inputs: [
|
|
{
|
|
key: 'kbList',
|
|
value: formData.kb.list,
|
|
type: FlowInputItemTypeEnum.custom,
|
|
label: '关联的知识库',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'similarity',
|
|
value: formData.kb.searchSimilarity,
|
|
type: FlowInputItemTypeEnum.slider,
|
|
label: '相似度',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'limit',
|
|
value: formData.kb.searchLimit,
|
|
type: FlowInputItemTypeEnum.slider,
|
|
label: '单次搜索上限',
|
|
connected: true
|
|
},
|
|
{
|
|
key: 'switch',
|
|
type: FlowInputItemTypeEnum.target,
|
|
label: '触发器',
|
|
connected: false
|
|
},
|
|
{
|
|
key: 'userChatInput',
|
|
type: FlowInputItemTypeEnum.target,
|
|
label: '用户问题',
|
|
connected: true
|
|
}
|
|
],
|
|
outputs: [
|
|
{
|
|
key: 'isEmpty',
|
|
targets: formData.kb.searchEmptyText
|
|
? [
|
|
{
|
|
moduleId: 'emptyText',
|
|
key: 'switch'
|
|
}
|
|
]
|
|
: [
|
|
{
|
|
moduleId: 'chatModule',
|
|
key: 'switch'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
key: 'unEmpty',
|
|
targets: [
|
|
{
|
|
moduleId: 'chatModule',
|
|
key: 'switch'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
key: 'quoteQA',
|
|
targets: [
|
|
{
|
|
moduleId: 'chatModule',
|
|
key: 'quoteQA'
|
|
}
|
|
]
|
|
}
|
|
],
|
|
position: {
|
|
x: 956.0838440206068,
|
|
y: 887.462827870246
|
|
},
|
|
moduleId: 'kbSearch'
|
|
},
|
|
...(formData.kb.searchEmptyText
|
|
? [
|
|
{
|
|
name: '指定回复',
|
|
flowType: FlowModuleTypeEnum.answerNode,
|
|
inputs: [
|
|
{
|
|
key: 'switch',
|
|
type: FlowInputItemTypeEnum.target,
|
|
label: '触发器',
|
|
connected: true
|
|
},
|
|
{
|
|
key: SpecialInputKeyEnum.answerText,
|
|
value: formData.kb.searchEmptyText,
|
|
type: FlowInputItemTypeEnum.textarea,
|
|
valueType: FlowValueTypeEnum.string,
|
|
label: '回复的内容',
|
|
connected: true
|
|
}
|
|
],
|
|
outputs: [],
|
|
position: {
|
|
x: 1553.5815811529146,
|
|
y: 637.8753731306779
|
|
},
|
|
moduleId: 'emptyText'
|
|
}
|
|
]
|
|
: []),
|
|
{
|
|
name: 'AI 对话',
|
|
flowType: FlowModuleTypeEnum.chatNode,
|
|
inputs: chatModelInput(formData),
|
|
showStatus: true,
|
|
outputs: [
|
|
{
|
|
key: 'answerText',
|
|
label: '模型回复',
|
|
description: '直接响应,无需配置',
|
|
type: 'hidden',
|
|
targets: []
|
|
},
|
|
{
|
|
key: 'finish',
|
|
label: '回复结束',
|
|
description: 'AI 回复完成后触发',
|
|
valueType: 'boolean',
|
|
type: 'source',
|
|
targets: []
|
|
}
|
|
],
|
|
position: {
|
|
x: 1551.71405495818,
|
|
y: 977.4911578918461
|
|
},
|
|
moduleId: 'chatModule'
|
|
}
|
|
];
|
|
|
|
export const appForm2Modules = (formData: EditFormType) => {
|
|
const modules = [
|
|
...userGuideTemplate(formData),
|
|
...(formData.kb.list.length > 0 ? kbTemplate(formData) : simpleChatTemplate(formData))
|
|
];
|
|
|
|
return modules as AppModuleItemType[];
|
|
};
|