diff --git a/client/public/locales/en/common.json b/client/public/locales/en/common.json
index 1e3ee46df..21da3b864 100644
--- a/client/public/locales/en/common.json
+++ b/client/public/locales/en/common.json
@@ -14,7 +14,6 @@
"UnKnow": "UnKnow",
"Warning": "Warning",
"app": {
- "Quote Prompt Settings": "Quote Prompt Settings",
"Advance App TestTip": "The current application is advanced editing mode \n. If you need to switch to [simple mode], please click the save button on the left",
"App Detail": "App Detail",
"Chat Logs Tips": "Logs record the app's online, shared, and API(chatId is existing) conversations",
@@ -40,7 +39,14 @@
"My Apps": "My Apps",
"Output Field Settings": "Output Field Settings",
"Paste Config": "Paste Config",
- "Variable Key Repeat Tip": "Variable Key Repeat"
+ "Quote Prompt Settings": "Quote Prompt Settings",
+ "Variable Key Repeat Tip": "Variable Key Repeat",
+ "module": {
+ "Custom Title Tip": "The title name is displayed during the conversation"
+ },
+ "modules": {
+ "Title is required": "Title is required"
+ }
},
"chat": {
"Admin Mark Content": "Corrected response",
@@ -81,6 +87,7 @@
"Copy": "Copy",
"Copy Successful": "Copy Successful",
"Course": "",
+ "Custom Title": "Custom Title",
"Delete": "Delete",
"Delete Failed": "Delete Failed",
"Delete Success": "Delete Successful",
diff --git a/client/public/locales/zh/common.json b/client/public/locales/zh/common.json
index eb910068f..b8606e96e 100644
--- a/client/public/locales/zh/common.json
+++ b/client/public/locales/zh/common.json
@@ -14,7 +14,6 @@
"UnKnow": "未知",
"Warning": "提示",
"app": {
- "Quote Prompt Settings": "引用提示词配置",
"Advance App TestTip": "当前应用为高级编排模式\n如需切换为【简易模式】请点击左侧保存按键",
"App Detail": "应用详情",
"Chat Logs Tips": "日志会记录该应用的在线、分享和 API(需填写 chatId) 对话记录",
@@ -40,7 +39,14 @@
"My Apps": "我的应用",
"Output Field Settings": "输出字段编辑",
"Paste Config": "粘贴配置",
- "Variable Key Repeat Tip": "变量 key 重复"
+ "Quote Prompt Settings": "引用提示词配置",
+ "Variable Key Repeat Tip": "变量 key 重复",
+ "module": {
+ "Custom Title Tip": "该标题名字会展示在对话过程中"
+ },
+ "modules": {
+ "Title is required": "模块名不能为空"
+ }
},
"chat": {
"Admin Mark Content": "纠正后的回复",
@@ -81,6 +87,7 @@
"Copy": "复制",
"Copy Successful": "复制成功",
"Course": "",
+ "Custom Title": "自定义标题",
"Delete": "删除",
"Delete Failed": "删除失败",
"Delete Success": "删除成功",
diff --git a/client/src/api/service/plugins.ts b/client/src/api/service/plugins.ts
index aa62a31b8..1bae574ea 100644
--- a/client/src/api/service/plugins.ts
+++ b/client/src/api/service/plugins.ts
@@ -1,8 +1,12 @@
import { GET, POST } from './request';
export const textCensor = (data: { text: string }) =>
- POST<{ code?: number; message: string }>('/plugins/censor/text_baidu', data).then((res) => {
- if (res?.code === 5000) {
- return Promise.reject(res.message);
- }
- });
+ POST<{ code?: number; message: string }>('/plugins/censor/text_baidu', data)
+ .then((res) => {
+ if (res?.code === 5000) {
+ return Promise.reject(res.message);
+ }
+ })
+ .catch((err) => {
+ return Promise.resolve('');
+ });
diff --git a/client/src/components/ChatBox/ResponseTags.tsx b/client/src/components/ChatBox/ResponseTags.tsx
index 0f68360eb..c61ddc568 100644
--- a/client/src/components/ChatBox/ResponseTags.tsx
+++ b/client/src/components/ChatBox/ResponseTags.tsx
@@ -1,5 +1,4 @@
import React, { useCallback, useMemo, useState } from 'react';
-import { ChatModuleEnum } from '@/constants/chat';
import { ChatHistoryItemResType, ChatItemType, QuoteItemType } from '@/types/chat';
import { Flex, BoxProps, useDisclosure } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
@@ -7,6 +6,8 @@ import { useGlobalStore } from '@/store/global';
import dynamic from 'next/dynamic';
import Tag from '../Tag';
import MyTooltip from '../MyTooltip';
+import { FlowModuleTypeEnum } from '@/constants/flow';
+
const QuoteModal = dynamic(() => import('./QuoteModal'), { ssr: false });
const ContextModal = dynamic(() => import('./ContextModal'), { ssr: false });
const WholeResponseModal = dynamic(() => import('./WholeResponseModal'), { ssr: false });
@@ -32,15 +33,15 @@ const ResponseTags = ({
const {
quoteList = [],
- completeMessages = [],
- tokens = 0
+ historyPreview = [],
+ runningTime = 0
} = useMemo(() => {
- const chatData = responseData.find((item) => item.moduleName === ChatModuleEnum.AIChat);
+ const chatData = responseData.find((item) => item.moduleType === FlowModuleTypeEnum.chatNode);
if (!chatData) return {};
return {
quoteList: chatData.quoteList,
- completeMessages: chatData.completeMessages,
- tokens: responseData.reduce((sum, item) => sum + (item.tokens || 0), 0)
+ historyPreview: chatData.historyPreview,
+ runningTime: responseData.reduce((sum, item) => sum + (item.runningTime || 0), 0)
};
}, [responseData]);
@@ -65,21 +66,21 @@ const ResponseTags = ({
)}
- {completeMessages.length > 0 && (
+ {historyPreview.length > 0 && (
setContextModalData(completeMessages)}
+ onClick={() => setContextModalData(historyPreview)}
>
- {completeMessages.length}条上下文
+ {historyPreview.length}条上下文
)}
- {isPc && tokens > 0 && (
+ {isPc && runningTime > 0 && (
- {tokens}Tokens
+ {runningTime}s
)}
diff --git a/client/src/components/ChatBox/WholeResponseModal.tsx b/client/src/components/ChatBox/WholeResponseModal.tsx
index e16e0aadd..7c12eff6b 100644
--- a/client/src/components/ChatBox/WholeResponseModal.tsx
+++ b/client/src/components/ChatBox/WholeResponseModal.tsx
@@ -21,7 +21,7 @@ const ResponseModal = ({
() =>
response.map((item) => {
const copy = { ...item };
- delete copy.completeMessages;
+ delete copy.historyPreview;
delete copy.quoteList;
return copy;
}),
diff --git a/client/src/components/Icon/index.tsx b/client/src/components/Icon/index.tsx
index cab8ec076..9fac92523 100644
--- a/client/src/components/Icon/index.tsx
+++ b/client/src/components/Icon/index.tsx
@@ -94,7 +94,7 @@ const MyIcon = ({ name, w = 'auto', h = 'auto', ...props }: { name: IconName } &
const [IconComponent, setIconComponent] = useState(null);
useEffect(() => {
- iconPaths[name]()
+ iconPaths[name]?.()
.then((icon) => {
setIconComponent({ as: icon.default });
})
diff --git a/client/src/constants/chat.ts b/client/src/constants/chat.ts
index 507e36698..473873978 100644
--- a/client/src/constants/chat.ts
+++ b/client/src/constants/chat.ts
@@ -52,14 +52,6 @@ export const ChatSourceMap = {
}
};
-export enum ChatModuleEnum {
- 'AIChat' = 'AI Chat',
- 'KBSearch' = 'KB Search',
- 'CQ' = 'Classify Question',
- 'Extract' = 'Content Extract',
- 'Http' = 'Http'
-}
-
export enum OutLinkTypeEnum {
'share' = 'share',
'iframe' = 'iframe'
diff --git a/client/src/constants/flow/ModuleTemplate.ts b/client/src/constants/flow/ModuleTemplate.ts
index 991534070..f62f3434c 100644
--- a/client/src/constants/flow/ModuleTemplate.ts
+++ b/client/src/constants/flow/ModuleTemplate.ts
@@ -26,12 +26,12 @@ export const welcomeTextTip =
'每次对话开始前,发送一个初始内容。支持标准 Markdown 语法,可使用的额外标记:\n[快捷按键]: 用户点击后可以直接发送该问题';
export const VariableModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.variable,
logo: '/imgs/module/variable.png',
name: '全局变量',
intro: '可以在对话开始前,要求用户填写一些内容作为本轮对话的变量。该模块位于开场引导之后。',
description:
'全局变量可以通过 {{变量key}} 的形式注入到其他模块 string 类型的输入中,例如:提示词、限定词等',
- flowType: FlowModuleTypeEnum.variable,
inputs: [
{
key: SystemInputEnum.variables,
@@ -43,10 +43,10 @@ export const VariableModule: FlowModuleTemplateType = {
outputs: []
};
export const UserGuideModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.userGuide,
logo: '/imgs/module/userGuide.png',
name: '用户引导',
intro: userGuideTip,
- flowType: FlowModuleTypeEnum.userGuide,
inputs: [
{
key: SystemInputEnum.welcomeText,
@@ -57,10 +57,10 @@ export const UserGuideModule: FlowModuleTemplateType = {
outputs: []
};
export const UserInputModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.questionInput,
logo: '/imgs/module/userChatInput.png',
name: '用户问题(对话入口)',
intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
- flowType: FlowModuleTypeEnum.questionInput,
inputs: [
{
key: SystemInputEnum.userChatInput,
@@ -79,10 +79,10 @@ export const UserInputModule: FlowModuleTemplateType = {
]
};
export const HistoryModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.historyNode,
logo: '/imgs/module/history.png',
name: '聊天记录',
intro: '用户输入的内容。该模块通常作为应用的入口,用户在发送消息后会首先执行该模块。',
- flowType: FlowModuleTypeEnum.historyNode,
inputs: [
{
key: 'maxContext',
@@ -110,10 +110,10 @@ export const HistoryModule: FlowModuleTemplateType = {
};
export const ChatModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.chatNode,
logo: '/imgs/module/AI.png',
name: 'AI 对话',
intro: 'AI 大模型对话',
- flowType: FlowModuleTypeEnum.chatNode,
showStatus: true,
inputs: [
{
@@ -209,10 +209,10 @@ export const ChatModule: FlowModuleTemplateType = {
};
export const KBSearchModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.kbSearchNode,
logo: '/imgs/module/db.png',
name: '知识库搜索',
intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。',
- flowType: FlowModuleTypeEnum.kbSearchNode,
showStatus: true,
inputs: [
{
@@ -280,11 +280,11 @@ export const KBSearchModule: FlowModuleTemplateType = {
};
export const AnswerModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.answerNode,
logo: '/imgs/module/reply.png',
name: '指定回复',
intro: '该模块可以直接回复一段指定的内容。常用于引导、提示',
description: '该模块可以直接回复一段指定的内容。常用于引导、提示',
- flowType: FlowModuleTypeEnum.answerNode,
inputs: [
Input_Template_TFSwitch,
{
@@ -308,40 +308,13 @@ export const AnswerModule: FlowModuleTemplateType = {
}
]
};
-export const TFSwitchModule: FlowModuleTemplateType = {
- logo: '',
- name: 'TF开关',
- intro: '可以判断输入的内容为 True 或者 False,从而执行不同操作。',
- flowType: FlowModuleTypeEnum.tfSwitchNode,
- inputs: [
- {
- key: SystemInputEnum.switch,
- type: FlowInputItemTypeEnum.target,
- label: '输入'
- }
- ],
- outputs: [
- {
- key: 'true',
- label: 'True',
- type: FlowOutputItemTypeEnum.source,
- targets: []
- },
- {
- key: 'false',
- label: 'False',
- type: FlowOutputItemTypeEnum.source,
- targets: []
- }
- ]
-};
export const ClassifyQuestionModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.classifyQuestion,
logo: '/imgs/module/cq.png',
name: '问题分类',
intro: '可以判断用户问题属于哪方面问题,从而执行不同的操作。',
description:
'根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于 laf 通用问题\n类型3: 关于 laf 代码问题\n类型4: 其他问题',
- flowType: FlowModuleTypeEnum.classifyQuestion,
showStatus: true,
inputs: [
{
@@ -398,11 +371,11 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = {
]
};
export const ContextExtractModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.contentExtract,
logo: '/imgs/module/extract.png',
name: '文本内容提取',
intro: '从文本中提取出指定格式的数据',
description: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等',
- flowType: FlowModuleTypeEnum.contentExtract,
showStatus: true,
inputs: [
Input_Template_TFSwitch,
@@ -458,11 +431,11 @@ export const ContextExtractModule: FlowModuleTemplateType = {
]
};
export const HttpModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.httpRequest,
logo: '/imgs/module/http.png',
name: 'HTTP模块',
intro: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
description: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)',
- flowType: FlowModuleTypeEnum.httpRequest,
showStatus: true,
inputs: [
{
@@ -487,11 +460,11 @@ export const HttpModule: FlowModuleTemplateType = {
]
};
export const EmptyModule: FlowModuleTemplateType = {
+ flowType: FlowModuleTypeEnum.empty,
logo: '/imgs/module/cq.png',
name: '该模块已被移除',
intro: '',
description: '',
- flowType: FlowModuleTypeEnum.empty,
inputs: [],
outputs: []
};
diff --git a/client/src/pages/api/openapi/v1/chat/completions.ts b/client/src/pages/api/openapi/v1/chat/completions.ts
index eeb84f0cf..f9553a276 100644
--- a/client/src/pages/api/openapi/v1/chat/completions.ts
+++ b/client/src/pages/api/openapi/v1/chat/completions.ts
@@ -154,11 +154,6 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
stream,
detail
});
- // console.log(responseData, '===', answerText);
-
- // if (!answerText) {
- // throw new Error('回复内容为空,可能模块编排出现问题');
- // }
// save chat
if (chatId) {
@@ -284,6 +279,7 @@ export async function dispatchModules({
// let storeData: Record = {}; // after module used
let chatResponse: ChatHistoryItemResType[] = []; // response request and save to database
let chatAnswerText = ''; // AI answer
+ let runningTime = Date.now();
function pushStore({
answerText = '',
@@ -292,7 +288,13 @@ export async function dispatchModules({
answerText?: string;
responseData?: ChatHistoryItemResType;
}) {
- responseData && chatResponse.push(responseData);
+ const time = Date.now();
+ responseData &&
+ chatResponse.push({
+ ...responseData,
+ runningTime: +((time - runningTime) / 1000).toFixed(2)
+ });
+ runningTime = time;
chatAnswerText += answerText;
}
function moduleInput(
diff --git a/client/src/pages/app/detail/components/AdEdit/components/modules/NodeCard.tsx b/client/src/pages/app/detail/components/AdEdit/components/modules/NodeCard.tsx
index 685135785..cd1d69975 100644
--- a/client/src/pages/app/detail/components/AdEdit/components/modules/NodeCard.tsx
+++ b/client/src/pages/app/detail/components/AdEdit/components/modules/NodeCard.tsx
@@ -6,7 +6,8 @@ import type { FlowModuleItemType } from '@/types/flow';
import MyTooltip from '@/components/MyTooltip';
import { QuestionOutlineIcon } from '@chakra-ui/icons';
import { useTranslation } from 'react-i18next';
-import { useCopyData } from '@/utils/tools';
+import { useEditTitle } from '@/hooks/useEditTitle';
+import { useToast } from '@/hooks/useToast';
type Props = FlowModuleItemType & {
children?: React.ReactNode | React.ReactNode[] | string;
@@ -22,29 +23,48 @@ const NodeCard = (props: Props) => {
minW = '300px',
onCopyNode,
onDelNode,
+ onChangeNode,
moduleId
} = props;
- const { copyData } = useCopyData();
const { t } = useTranslation();
const theme = useTheme();
+ const { toast } = useToast();
+
+ // custom title edit
+ const { onOpenModal, EditModal: EditTitleModal } = useEditTitle({
+ title: t('common.Custom Title'),
+ placeholder: t('app.module.Custom Title Tip') || ''
+ });
const menuList = useMemo(
() => [
+ {
+ icon: 'edit',
+ label: t('common.Rename'),
+ onClick: () =>
+ onOpenModal({
+ defaultVal: name,
+ onSuccess: (e) => {
+ if (!e) {
+ return toast({
+ title: t('app.modules.Title is required'),
+ status: 'warning'
+ });
+ }
+ onChangeNode({
+ moduleId,
+ type: 'attr',
+ key: 'name',
+ value: e
+ });
+ }
+ })
+ },
{
icon: 'copy',
label: t('common.Copy'),
onClick: () => onCopyNode(moduleId)
},
- // {
- // icon: 'settingLight',
- // label: t('app.Copy Module Config'),
- // onClick: () => {
- // const copyProps = { ...props };
- // delete copyProps.children;
- // delete copyProps.children;
- // console.log(copyProps);
- // }
- // },
{
icon: 'delete',
label: t('common.Delete'),
@@ -100,6 +120,7 @@ const NodeCard = (props: Props) => {
{children}
+
);
};
diff --git a/client/src/pages/app/detail/components/AdEdit/index.tsx b/client/src/pages/app/detail/components/AdEdit/index.tsx
index b52bbc542..0af69c5c5 100644
--- a/client/src/pages/app/detail/components/AdEdit/index.tsx
+++ b/client/src/pages/app/detail/components/AdEdit/index.tsx
@@ -276,62 +276,43 @@ const AppEdit = ({ app, onCloseSettings }: Props) => {
setNodes((nodes) =>
nodes.map((node) => {
if (node.id !== moduleId) return node;
+
+ const updateObj: Record = {};
+
if (type === 'inputs') {
- return {
- ...node,
- data: {
- ...node.data,
- inputs: node.data.inputs.map((item) => (item.key === key ? value : item))
- }
- };
- }
- if (type === 'addInput') {
+ updateObj.inputs = node.data.inputs.map((item) => (item.key === key ? value : item));
+ } else if (type === 'addInput') {
const input = node.data.inputs.find((input) => input.key === value.key);
if (input) {
toast({
status: 'warning',
title: 'key 重复'
});
- return {
- ...node,
- data: {
- ...node.data,
- inputs: node.data.inputs
- }
- };
+ updateObj.inputs = node.data.inputs;
+ } else {
+ updateObj.inputs = node.data.inputs.concat(value);
}
- return {
- ...node,
- data: {
- ...node.data,
- inputs: node.data.inputs.concat(value)
- }
- };
- }
- if (type === 'delInput') {
+ } else if (type === 'delInput') {
onDelEdge({ moduleId, targetHandle: key });
- return {
- ...node,
- data: {
- ...node.data,
- inputs: node.data.inputs.filter((item) => item.key !== key)
- }
- };
+ updateObj.inputs = node.data.inputs.filter((item) => item.key !== key);
+ } else if (type === 'attr') {
+ updateObj[key] = value;
+ } else if (type === 'outputs') {
+ // del output connect
+ const delOutputs = node.data.outputs.filter(
+ (item) => !value.find((output: FlowOutputTargetItemType) => output.key === item.key)
+ );
+ delOutputs.forEach((output) => {
+ onDelEdge({ moduleId, sourceHandle: output.key });
+ });
+ updateObj.outputs = value;
}
- // del output connect
- const delOutputs = node.data.outputs.filter(
- (item) => !value.find((output: FlowOutputTargetItemType) => output.key === item.key)
- );
- delOutputs.forEach((output) => {
- onDelEdge({ moduleId, sourceHandle: output.key });
- });
-
return {
...node,
data: {
...node.data,
- outputs: value
+ ...updateObj
}
};
})
diff --git a/client/src/service/events/pushBill.ts b/client/src/service/events/pushBill.ts
index 853c3b895..6f1d7f9de 100644
--- a/client/src/service/events/pushBill.ts
+++ b/client/src/service/events/pushBill.ts
@@ -30,7 +30,7 @@ export const pushTaskBill = async ({
total,
source,
list: response.map((item) => ({
- moduleName: item.moduleName,
+ moduleType: item.moduleType,
amount: item.price || 0,
model: item.model,
tokenLen: item.tokens
diff --git a/client/src/service/models/chat.ts b/client/src/service/models/chat.ts
index 57c713385..220e344a0 100644
--- a/client/src/service/models/chat.ts
+++ b/client/src/service/models/chat.ts
@@ -62,24 +62,7 @@ const ChatSchema = new Schema({
default: ''
},
[TaskResponseKeyEnum.responseData]: {
- type: [
- {
- moduleName: String,
- price: String,
- model: String,
- tokens: Number,
- question: String,
- answer: String,
- temperature: Number,
- maxToken: Number,
- quoteList: Array,
- completeMessages: Array,
- similarity: Number,
- limit: Number,
- cqList: Array,
- cqResult: String
- }
- ],
+ type: Array,
default: []
}
}
diff --git a/client/src/service/moduleDispatch/agent/classifyQuestion.ts b/client/src/service/moduleDispatch/agent/classifyQuestion.ts
index 96958e392..00d4712bc 100644
--- a/client/src/service/moduleDispatch/agent/classifyQuestion.ts
+++ b/client/src/service/moduleDispatch/agent/classifyQuestion.ts
@@ -1,7 +1,7 @@
import { adaptChat2GptMessages } from '@/utils/common/adapt/message';
import { ChatContextFilter } from '@/service/common/tiktoken';
import type { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
-import { ChatModuleEnum, ChatRoleEnum, TaskResponseKeyEnum } from '@/constants/chat';
+import { ChatRoleEnum, TaskResponseKeyEnum } from '@/constants/chat';
import { getAIChatApi, axiosConfig } from '@/service/lib/openai';
import type { ClassifyQuestionAgentItemType } from '@/types/app';
import { countModelPrice } from '@/service/events/pushBill';
@@ -9,6 +9,7 @@ import { UserModelSchema } from '@/types/mongoSchema';
import { getModel } from '@/service/utils/data';
import { SystemInputEnum } from '@/constants/app';
import { SpecialInputKeyEnum } from '@/constants/flow';
+import { FlowModuleTypeEnum } from '@/constants/flow';
export type CQProps = {
systemPrompt?: string;
@@ -95,7 +96,7 @@ export const dispatchClassifyQuestion = async (props: Record): Prom
return {
[result.key]: 1,
[TaskResponseKeyEnum.responseData]: {
- moduleName: ChatModuleEnum.CQ,
+ moduleType: FlowModuleTypeEnum.classifyQuestion,
price: userOpenaiAccount?.key ? 0 : countModelPrice({ model: agentModel, tokens }),
model: getModel(agentModel)?.name || agentModel,
tokens,
diff --git a/client/src/service/moduleDispatch/agent/extract.ts b/client/src/service/moduleDispatch/agent/extract.ts
index d422eaa80..703b23469 100644
--- a/client/src/service/moduleDispatch/agent/extract.ts
+++ b/client/src/service/moduleDispatch/agent/extract.ts
@@ -1,13 +1,14 @@
import { adaptChat2GptMessages } from '@/utils/common/adapt/message';
import { ChatContextFilter } from '@/service/common/tiktoken';
import type { ChatHistoryItemResType, ChatItemType } from '@/types/chat';
-import { ChatModuleEnum, ChatRoleEnum, TaskResponseKeyEnum } from '@/constants/chat';
+import { ChatRoleEnum, TaskResponseKeyEnum } from '@/constants/chat';
import { getAIChatApi, axiosConfig } from '@/service/lib/openai';
import type { ContextExtractAgentItemType } from '@/types/app';
import { ContextExtractEnum } from '@/constants/flow/flowField';
import { countModelPrice } from '@/service/events/pushBill';
import { UserModelSchema } from '@/types/mongoSchema';
import { getModel } from '@/service/utils/data';
+import { FlowModuleTypeEnum } from '@/constants/flow';
export type Props = {
userOpenaiAccount: UserModelSchema['openaiAccount'];
@@ -118,7 +119,7 @@ export async function dispatchContentExtract({
[ContextExtractEnum.fields]: JSON.stringify(arg),
...arg,
[TaskResponseKeyEnum.responseData]: {
- moduleName: ChatModuleEnum.Extract,
+ moduleType: FlowModuleTypeEnum.contentExtract,
price: userOpenaiAccount?.key ? 0 : countModelPrice({ model: agentModel, tokens }),
model: getModel(agentModel)?.name || agentModel,
tokens,
diff --git a/client/src/service/moduleDispatch/chat/oneapi.ts b/client/src/service/moduleDispatch/chat/oneapi.ts
index 273a578f6..d3d831226 100644
--- a/client/src/service/moduleDispatch/chat/oneapi.ts
+++ b/client/src/service/moduleDispatch/chat/oneapi.ts
@@ -3,7 +3,7 @@ import { sseResponse } from '@/service/utils/tools';
import { ChatContextFilter } from '@/service/common/tiktoken';
import type { ChatItemType, QuoteItemType } from '@/types/chat';
import type { ChatHistoryItemResType } from '@/types/chat';
-import { ChatModuleEnum, ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat';
+import { ChatRoleEnum, sseResponseEventEnum } from '@/constants/chat';
import { SSEParseData, parseStreamChunk } from '@/utils/sse';
import { textAdaptGptResponse } from '@/utils/adapt';
import { getAIChatApi, axiosConfig } from '@/service/lib/openai';
@@ -20,6 +20,7 @@ import { adaptChat2GptMessages } from '@/utils/common/adapt/message';
import { defaultQuotePrompt, defaultQuoteTemplate } from '@/prompts/core/AIChat';
import type { AIChatProps } from '@/types/core/aiChat';
import { replaceVariable } from '@/utils/common/tools/text';
+import { FlowModuleTypeEnum } from '@/constants/flow';
export type ChatProps = AIChatProps & {
res: NextApiResponse;
@@ -175,15 +176,14 @@ export const dispatchChatCompletion = async (props: Record): Promis
return {
[TaskResponseKeyEnum.answerText]: answerText,
[TaskResponseKeyEnum.responseData]: {
- moduleName: ChatModuleEnum.AIChat,
+ moduleType: FlowModuleTypeEnum.chatNode,
price: userOpenaiAccount?.key ? 0 : countModelPrice({ model, tokens: totalTokens }),
model: modelConstantsData.name,
tokens: totalTokens,
question: userChatInput,
- answer: answerText,
maxToken: max_tokens,
quoteList: filterQuoteQA,
- completeMessages
+ historyPreview: getHistoryPreview(completeMessages)
},
finish: true
};
@@ -371,3 +371,14 @@ async function streamResponse({
answer
};
}
+
+function getHistoryPreview(completeMessages: ChatItemType[]) {
+ return completeMessages.map((item, i) => {
+ if (item.obj === ChatRoleEnum.System) return item;
+ if (i >= completeMessages.length - 2) return item;
+ return {
+ ...item,
+ value: item.value.length > 15 ? `${item.value.slice(0, 15)}...` : item.value
+ };
+ });
+}
diff --git a/client/src/service/moduleDispatch/kb/search.ts b/client/src/service/moduleDispatch/kb/search.ts
index 6813846f6..d384031c9 100644
--- a/client/src/service/moduleDispatch/kb/search.ts
+++ b/client/src/service/moduleDispatch/kb/search.ts
@@ -1,11 +1,12 @@
import { PgClient } from '@/service/pg';
import type { ChatHistoryItemResType } from '@/types/chat';
-import { ChatModuleEnum, TaskResponseKeyEnum } from '@/constants/chat';
+import { TaskResponseKeyEnum } from '@/constants/chat';
import { getVector } from '@/pages/api/openapi/plugin/vector';
import { countModelPrice } from '@/service/events/pushBill';
import type { SelectedKbType } from '@/types/plugin';
import type { QuoteItemType } from '@/types/chat';
import { PgDatasetTableName } from '@/constants/plugin';
+import { FlowModuleTypeEnum } from '@/constants/flow';
type KBSearchProps = {
kbList: SelectedKbType;
@@ -57,7 +58,7 @@ export async function dispatchKBSearch(props: Record): Promise 0 ? true : undefined,
quoteQA: searchRes,
responseData: {
- moduleName: ChatModuleEnum.KBSearch,
+ moduleType: FlowModuleTypeEnum.kbSearchNode,
price: countModelPrice({ model: vectorModel.model, tokens: tokenLen }),
model: vectorModel.name,
tokens: tokenLen,
diff --git a/client/src/service/moduleDispatch/tools/http.ts b/client/src/service/moduleDispatch/tools/http.ts
index fb0d927f0..8b645829b 100644
--- a/client/src/service/moduleDispatch/tools/http.ts
+++ b/client/src/service/moduleDispatch/tools/http.ts
@@ -1,7 +1,8 @@
-import { ChatModuleEnum, TaskResponseKeyEnum } from '@/constants/chat';
+import { TaskResponseKeyEnum } from '@/constants/chat';
import { HttpPropsEnum } from '@/constants/flow/flowField';
import { ChatHistoryItemResType } from '@/types/chat';
import type { NextApiResponse } from 'next';
+import { FlowModuleTypeEnum } from '@/constants/flow';
export type HttpRequestProps = {
res: NextApiResponse;
@@ -26,7 +27,7 @@ export const dispatchHttpRequest = async (props: Record): Promise): Promise(
}
// another error
- let msg = error?.response?.statusText || error?.message || '请求错误';
+ let msg = '';
if ((code < 200 || code >= 400) && !message) {
- msg = error?.message || '请求错误';
+ msg = error?.response?.statusText || error?.message || '请求错误';
if (typeof error === 'string') {
msg = error;
} else if (proxyError[error?.code]) {
@@ -59,7 +59,7 @@ export const jsonRes = (
res.status(code).json({
code,
statusText: '',
- message: msg,
+ message: message || msg,
data: data !== undefined ? data : null
});
};
diff --git a/client/src/types/chat.d.ts b/client/src/types/chat.d.ts
index 86802b887..485e56bf6 100644
--- a/client/src/types/chat.d.ts
+++ b/client/src/types/chat.d.ts
@@ -4,6 +4,7 @@ import { TaskResponseKeyEnum } from '@/constants/chat';
import { ClassifyQuestionAgentItemType } from './app';
import { ChatItemSchema } from './mongoSchema';
import { KbDataItemType } from './plugin';
+import { FlowModuleTypeEnum } from '@/constants/flow';
export type ExportChatType = 'md' | 'pdf' | 'html';
@@ -46,19 +47,20 @@ export type QuoteItemType = KbDataItemType & {
kb_id: string;
};
+// response data
export type ChatHistoryItemResType = {
- moduleName: string;
+ moduleType: `${FlowModuleTypeEnum}`;
price: number;
+ runningTime?: number;
model?: string;
tokens?: number;
// chat
- answer?: string;
question?: string;
temperature?: number;
maxToken?: number;
quoteList?: QuoteItemType[];
- completeMessages?: ChatItemType[];
+ historyPreview?: ChatItemType[]; // completion context array. history will slice
// kb search
similarity?: number;
diff --git a/client/src/types/flow.d.ts b/client/src/types/flow.d.ts
index 69eb31bf7..2d4086ecb 100644
--- a/client/src/types/flow.d.ts
+++ b/client/src/types/flow.d.ts
@@ -10,7 +10,7 @@ import { FlowModuleTypeEnum } from '@/constants/flow';
export type FlowModuleItemChangeProps = {
moduleId: string;
- type: 'inputs' | 'outputs' | 'addInput' | 'delInput';
+ type: 'attr' | 'inputs' | 'outputs' | 'addInput' | 'delInput';
key: string;
value: any;
};
@@ -48,12 +48,12 @@ export type FlowOutputItemType = {
};
export type FlowModuleTemplateType = {
+ flowType: `${FlowModuleTypeEnum}`; // unique
logo: string;
name: string;
description?: string;
intro: string;
- flowType: `${FlowModuleTypeEnum}`;
- showStatus?: boolean;
+ showStatus?: boolean; // chatting response step status
inputs: FlowInputItemType[];
outputs: FlowOutputItemType[];
};
diff --git a/client/src/utils/adapt.ts b/client/src/utils/adapt.ts
index a581e276d..3dd231c1d 100644
--- a/client/src/utils/adapt.ts
+++ b/client/src/utils/adapt.ts
@@ -92,8 +92,8 @@ export const appModule2FlowNode = ({
// replace item data
const moduleItem: FlowModuleItemType = {
- ...item,
...template,
+ ...item,
inputs: concatInputs.map((templateInput) => {
// use latest inputs
const itemInput = item.inputs.find((item) => item.key === templateInput.key) || templateInput;