From 9a31407a01d41c247d063c665832ee1348389ffe Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Fri, 4 Aug 2023 18:14:36 +0800 Subject: [PATCH] feat: chat status --- client/public/locales/en/common.json | 1 + client/public/locales/zh/common.json | 1 + client/src/api/fetch.ts | 11 ++- .../src/components/ChatBox/index.module.scss | 13 +++ client/src/components/ChatBox/index.tsx | 62 ++++++++++++-- client/src/components/Markdown/index.tsx | 2 +- client/src/constants/chat.ts | 5 +- client/src/constants/flow/ModuleTemplate.ts | 83 +++++++++++++------ .../pages/api/openapi/v1/chat/completions.ts | 40 ++++++++- .../AdEdit/components/TemplateList.tsx | 5 +- .../app/detail/components/AdEdit/index.tsx | 2 + .../service/moduleDispatch/agent/extract.ts | 3 + client/src/types/app.d.ts | 9 +- client/src/types/chat.d.ts | 3 +- client/src/types/flow.d.ts | 1 + client/src/utils/app.ts | 10 +++ 16 files changed, 205 insertions(+), 46 deletions(-) diff --git a/client/public/locales/en/common.json b/client/public/locales/en/common.json index 949de6c63..9adb16650 100644 --- a/client/public/locales/en/common.json +++ b/client/public/locales/en/common.json @@ -3,6 +3,7 @@ "Cancel": "No", "Confirm": "Yes", "Warning": "Warning", + "Running": "Running", "app": { "App Detail": "App Detail", "Confirm Del App Tip": "Confirm to delete the app and all its chats", diff --git a/client/public/locales/zh/common.json b/client/public/locales/zh/common.json index d25a0d370..5aa0cea43 100644 --- a/client/public/locales/zh/common.json +++ b/client/public/locales/zh/common.json @@ -3,6 +3,7 @@ "Cancel": "取消", "Confirm": "确认", "Warning": "提示", + "Running": "运行中", "app": { "App Detail": "应用详情", "Confirm Del App Tip": "确认删除该应用及其所有聊天记录?", diff --git a/client/src/api/fetch.ts b/client/src/api/fetch.ts index 942f93a36..bce777db5 100644 --- a/client/src/api/fetch.ts +++ b/client/src/api/fetch.ts @@ -2,11 +2,12 @@ import { sseResponseEventEnum, TaskResponseKeyEnum } from '@/constants/chat'; import { getErrText } from '@/utils/tools'; import { parseStreamChunk, SSEParseData } from '@/utils/sse'; import type { ChatHistoryItemResType } from '@/types/chat'; +import { StartChatFnProps } from '@/components/ChatBox'; interface StreamFetchProps { url?: string; data: Record; - onMessage: (text: string) => void; + onMessage: StartChatFnProps['generatingMessage']; abortSignal: AbortController; } export const streamFetch = ({ @@ -71,8 +72,14 @@ export const streamFetch = ({ if (eventName === sseResponseEventEnum.answer && data !== '[DONE]') { const answer: string = data?.choices?.[0].delta.content || ''; - onMessage(answer); + onMessage({ text: answer }); responseText += answer; + } else if ( + eventName === sseResponseEventEnum.moduleStatus && + data?.name && + data?.status + ) { + onMessage(data); } else if ( eventName === sseResponseEventEnum.appStreamResponse && Array.isArray(data) diff --git a/client/src/components/ChatBox/index.module.scss b/client/src/components/ChatBox/index.module.scss index 477d13f08..e8342cca3 100644 --- a/client/src/components/ChatBox/index.module.scss +++ b/client/src/components/ChatBox/index.module.scss @@ -28,3 +28,16 @@ } } } + +.statusAnimation { + animation: statusBox 0.8s linear infinite alternate; +} +@keyframes statusBox { + 0% { + opacity: 1; + } + + 100% { + opacity: 0.11; + } +} diff --git a/client/src/components/ChatBox/index.tsx b/client/src/components/ChatBox/index.tsx index c7936e5b3..4133ed66f 100644 --- a/client/src/components/ChatBox/index.tsx +++ b/client/src/components/ChatBox/index.tsx @@ -39,6 +39,7 @@ import { htmlTemplate } from '@/constants/common'; import { useRouter } from 'next/router'; import { useGlobalStore } from '@/store/global'; import { TaskResponseKeyEnum, getDefaultChatVariables } from '@/constants/chat'; +import { useTranslation } from 'react-i18next'; import MyIcon from '@/components/Icon'; import Avatar from '@/components/Avatar'; @@ -51,11 +52,12 @@ const ResponseDetailModal = dynamic(() => import('./ResponseDetailModal')); import styles from './index.module.scss'; const textareaMinH = '22px'; +type generatingMessageProps = { text?: string; name?: string; status?: 'running' | 'finish' }; export type StartChatFnProps = { messages: MessageItemType[]; controller: AbortController; variables: Record; - generatingMessage: (text: string) => void; + generatingMessage: (e: generatingMessageProps) => void; }; export type ComponentRef = { @@ -153,6 +155,7 @@ const ChatBox = ( const ChatBoxRef = useRef(null); const theme = useTheme(); const router = useRouter(); + const { t } = useTranslation(); const { copyData } = useCopyData(); const { toast } = useToast(); const { isPc } = useGlobalStore(); @@ -164,7 +167,9 @@ const ChatBox = ( const [chatHistory, setChatHistory] = useState([]); const isChatting = useMemo( - () => chatHistory[chatHistory.length - 1]?.status === 'loading', + () => + chatHistory[chatHistory.length - 1] && + chatHistory[chatHistory.length - 1]?.status !== 'finish', [chatHistory] ); const variableIsFinish = useMemo(() => { @@ -209,13 +214,23 @@ const ChatBox = ( ); // eslint-disable-next-line react-hooks/exhaustive-deps const generatingMessage = useCallback( - (text: string) => { + ({ text = '', status, name }: generatingMessageProps) => { setChatHistory((state) => state.map((item, index) => { if (index !== state.length - 1) return item; return { ...item, - value: item.value + text + ...(text + ? { + value: item.value + text + } + : {}), + ...(status && name + ? { + status, + moduleName: name + } + : {}) }; }) ); @@ -418,6 +433,21 @@ const ChatBox = ( !welcomeText, [chatHistory.length, showEmptyIntro, variableModules, welcomeText] ); + const statusBoxData = useMemo(() => { + const colorMap = { + loading: '#67c13b', + running: '#67c13b', + finish: 'myBlue.600' + }; + if (!isChatting) return; + const chatContent = chatHistory[chatHistory.length - 1]; + if (!chatContent) return; + + return { + bg: colorMap[chatContent.status] || colorMap.loading, + name: t(chatContent.moduleName || 'Running') + }; + }, [chatHistory, isChatting, t]); useEffect(() => { return () => { @@ -595,7 +625,7 @@ const ChatBox = ( )} {item.obj === 'AI' && ( <> - + @@ -635,6 +665,28 @@ const ChatBox = ( )} + {statusBoxData && index === chatHistory.length - 1 && ( + + + + {statusBoxData.name} + + + )} diff --git a/client/src/components/Markdown/index.tsx b/client/src/components/Markdown/index.tsx index aaccb671f..5134a076a 100644 --- a/client/src/components/Markdown/index.tsx +++ b/client/src/components/Markdown/index.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useRef } from 'react'; +import React, { useMemo } from 'react'; import ReactMarkdown from 'react-markdown'; import RemarkGfm from 'remark-gfm'; import RemarkMath from 'remark-math'; diff --git a/client/src/constants/chat.ts b/client/src/constants/chat.ts index b51b5f619..e3c71f004 100644 --- a/client/src/constants/chat.ts +++ b/client/src/constants/chat.ts @@ -3,9 +3,8 @@ import dayjs from 'dayjs'; export enum sseResponseEventEnum { error = 'error', answer = 'answer', - chatResponse = 'chatResponse', // - appStreamResponse = 'appStreamResponse', // sse response request - moduleFetchResponse = 'moduleFetchResponse' // http module sse response + moduleStatus = 'moduleStatus', + appStreamResponse = 'appStreamResponse' // sse response request } export enum ChatRoleEnum { diff --git a/client/src/constants/flow/ModuleTemplate.ts b/client/src/constants/flow/ModuleTemplate.ts index 6ad0ecb8d..a30206915 100644 --- a/client/src/constants/flow/ModuleTemplate.ts +++ b/client/src/constants/flow/ModuleTemplate.ts @@ -114,6 +114,7 @@ export const ChatModule: FlowModuleTemplateType = { name: 'AI 对话', intro: 'AI 大模型对话', flowType: FlowModuleTypeEnum.chatNode, + showStatus: true, inputs: [ { key: 'model', @@ -203,6 +204,7 @@ export const KBSearchModule: FlowModuleTemplateType = { name: '知识库搜索', intro: '去知识库中搜索对应的答案。可作为 AI 对话引用参考。', flowType: FlowModuleTypeEnum.kbSearchNode, + showStatus: true, inputs: [ { key: 'kbList', @@ -321,6 +323,7 @@ export const ClassifyQuestionModule: FlowModuleTemplateType = { description: '根据用户的历史记录和当前问题判断该次提问的类型。可以添加多组问题类型,下面是一个模板例子:\n类型1: 打招呼\n类型2: 关于 laf 通用问题\n类型3: 关于 laf 代码问题\n类型4: 其他问题', flowType: FlowModuleTypeEnum.classifyQuestion, + showStatus: true, inputs: [ { key: 'systemPrompt', @@ -381,6 +384,7 @@ export const ContextExtractModule: FlowModuleTemplateType = { intro: '从文本中提取出指定格式的数据', description: '可从文本中提取指定的数据,例如:sql语句、搜索关键词、代码等', flowType: FlowModuleTypeEnum.contentExtract, + showStatus: true, inputs: [ Input_Template_TFSwitch, { @@ -441,6 +445,7 @@ export const HttpModule: FlowModuleTemplateType = { intro: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)', description: '可以发出一个 HTTP POST 请求,实现更为复杂的操作(联网搜索、数据库查询等)', flowType: FlowModuleTypeEnum.httpRequest, + showStatus: true, inputs: [ { key: HttpPropsEnum.url, @@ -507,10 +512,11 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = modules: [ { moduleId: 'userChatInput', + name: '用户问题(对话入口)', flowType: 'questionInput', position: { - x: 506.7143912167368, - y: 1601.0230108651226 + x: 464.32198615344566, + y: 1602.2698463081606 }, inputs: [ { @@ -537,6 +543,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'history', + name: '聊天记录', flowType: 'historyNode', position: { x: 452.5466249541586, @@ -576,17 +583,19 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'chatModule', + name: 'AI 对话', flowType: 'chatNode', + showStatus: true, position: { - x: 998.0312473867093, - y: 803.8586941051353 + x: 1150.8317145593148, + y: 957.9676672880053 }, inputs: [ { key: 'model', type: 'custom', label: '对话模型', - value: 'gpt-3.5-turbo', + value: 'gpt-3.5-turbo-16k', list: [], connected: true }, @@ -614,9 +623,9 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = key: 'maxToken', type: 'custom', label: '回复上限', - value: 2000, + value: 8000, min: 100, - max: 4000, + max: 16000, step: 50, markList: [ { @@ -624,8 +633,8 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = value: 100 }, { - label: '4000', - value: 4000 + label: '16000', + value: 16000 } ], connected: true @@ -712,6 +721,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = modules: [ { moduleId: 'userGuide', + name: '用户引导', flowType: 'userGuide', position: { x: 454.98510354678695, @@ -730,6 +740,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'userChatInput', + name: '用户问题(对话入口)', flowType: 'questionInput', position: { x: 464.32198615344566, @@ -764,6 +775,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'history', + name: '聊天记录', flowType: 'historyNode', position: { x: 452.5466249541586, @@ -803,7 +815,9 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'kbSearch', + name: '知识库搜索', flowType: 'kbSearchNode', + showStatus: true, position: { x: 956.0838440206068, y: 887.462827870246 @@ -916,7 +930,9 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'chatModule', + name: 'AI 对话', flowType: 'chatNode', + showStatus: true, position: { x: 1546.0823206390796, y: 1008.9827344021824 @@ -926,7 +942,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = key: 'model', type: 'custom', label: '对话模型', - value: 'gpt-3.5-turbo', + value: 'gpt-3.5-turbo-16k', list: [], connected: true }, @@ -954,9 +970,9 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = key: 'maxToken', type: 'custom', label: '回复上限', - value: 2000, + value: 8000, min: 100, - max: 4000, + max: 16000, step: 50, markList: [ { @@ -964,8 +980,8 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = value: 100 }, { - label: '4000', - value: 4000 + label: '16000', + value: 16000 } ], connected: true @@ -1044,6 +1060,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: '2752oj', + name: '指定回复', flowType: 'answerNode', position: { x: 1542.9271243684725, @@ -1080,6 +1097,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = modules: [ { moduleId: 'userGuide', + name: '用户引导', flowType: 'userGuide', position: { x: 447.98520778293346, @@ -1098,6 +1116,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'variable', + name: '全局变量', flowType: 'variable', position: { x: 444.0369195277651, @@ -1146,6 +1165,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'userChatInput', + name: '用户问题(对话入口)', flowType: 'questionInput', position: { x: 464.32198615344566, @@ -1176,6 +1196,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'history', + name: '聊天记录', flowType: 'historyNode', position: { x: 452.5466249541586, @@ -1215,7 +1236,9 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'chatModule', + name: 'AI 对话', flowType: 'chatNode', + showStatus: true, position: { x: 981.9682828103937, y: 890.014595014464 @@ -1225,7 +1248,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = key: 'model', type: 'custom', label: '对话模型', - value: 'gpt-3.5-turbo', + value: 'gpt-3.5-turbo-16k', list: [], connected: true }, @@ -1253,9 +1276,9 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = key: 'maxToken', type: 'custom', label: '回复上限', - value: 2000, + value: 8000, min: 100, - max: 4000, + max: 16000, step: 50, markList: [ { @@ -1263,8 +1286,8 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = value: 100 }, { - label: '4000', - value: 4000 + label: '16000', + value: 16000 } ], connected: true @@ -1351,6 +1374,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = modules: [ { moduleId: '7z5g5h', + name: '用户问题(对话入口)', flowType: 'questionInput', position: { x: 198.56612928723575, @@ -1389,6 +1413,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'xj0c9p', + name: '聊天记录', flowType: 'historyNode', position: { x: 194.99102398958047, @@ -1428,7 +1453,9 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'remuj3', + name: '问题分类', flowType: 'classifyQuestion', + showStatus: true, position: { x: 672.9092284362648, y: 1077.557793775116 @@ -1535,6 +1562,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'a99p6z', + name: '指定回复', flowType: 'answerNode', position: { x: 1304.2886011902247, @@ -1563,6 +1591,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'iejcou', + name: '指定回复', flowType: 'answerNode', position: { x: 1294.2531189034548, @@ -1591,7 +1620,9 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'nlfwkc', + name: 'AI 对话', flowType: 'chatNode', + showStatus: true, position: { x: 1821.979893659983, y: 1104.6583548423682 @@ -1720,6 +1751,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 's4v9su', + name: '聊天记录', flowType: 'historyNode', position: { x: 193.3803955457983, @@ -1759,22 +1791,20 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'fljhzy', + name: '知识库搜索', flowType: 'kbSearchNode', + showStatus: true, position: { x: 1305.5374262228029, y: 1120.0404921820218 }, inputs: [ { - key: 'kbList', type: 'custom', label: '关联的知识库', - value: [ - { - kbId: '646627f4f7b896cfd8910e24' - } - ], list: [], + key: 'kbList', + value: [], connected: true }, { @@ -1876,6 +1906,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'q9equb', + name: '用户引导', flowType: 'userGuide', position: { x: 191.4857498376603, @@ -1895,6 +1926,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: 'tc90wz', + name: '指定回复', flowType: 'answerNode', position: { x: 1828.4596416688908, @@ -1923,6 +1955,7 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] = }, { moduleId: '5v78ap', + name: '指定回复', flowType: 'answerNode', position: { x: 1294.814522053934, diff --git a/client/src/pages/api/openapi/v1/chat/completions.ts b/client/src/pages/api/openapi/v1/chat/completions.ts index 1766365bd..48d82e73e 100644 --- a/client/src/pages/api/openapi/v1/chat/completions.ts +++ b/client/src/pages/api/openapi/v1/chat/completions.ts @@ -116,10 +116,12 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex } // 创建响应流 - res.setHeader('Content-Type', 'text/event-stream;charset=utf-8'); - res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('X-Accel-Buffering', 'no'); - res.setHeader('Cache-Control', 'no-cache, no-transform'); + if (stream) { + res.setHeader('Content-Type', 'text/event-stream;charset=utf-8'); + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('X-Accel-Buffering', 'no'); + res.setHeader('Cache-Control', 'no-cache, no-transform'); + } /* start process */ const { responseData, answerText } = await dispatchModules({ @@ -320,6 +322,14 @@ export async function dispatchModules({ if (res.closed) return Promise.resolve(); console.log('run=========', module.flowType); + if (stream && module.showStatus) { + responseStatus({ + res, + name: module.name, + status: 'running' + }); + } + // get fetch params const params: Record = {}; module.inputs.forEach((item: any) => { @@ -370,7 +380,9 @@ function loadModules( return modules.map((module) => { return { moduleId: module.moduleId, + name: module.name, flowType: module.flowType, + showStatus: module.showStatus, inputs: module.inputs .filter((item) => item.connected) // filter unconnected target input .map((item) => { @@ -401,3 +413,23 @@ function loadModules( }; }); } + +function responseStatus({ + res, + status, + name +}: { + res: NextApiResponse; + status: 'running' | 'finish'; + name?: string; +}) { + if (!name) return; + sseResponse({ + res, + event: sseResponseEventEnum.moduleStatus, + data: JSON.stringify({ + status, + name + }) + }); +} diff --git a/client/src/pages/app/detail/components/AdEdit/components/TemplateList.tsx b/client/src/pages/app/detail/components/AdEdit/components/TemplateList.tsx index fbd272de9..812699de1 100644 --- a/client/src/pages/app/detail/components/AdEdit/components/TemplateList.tsx +++ b/client/src/pages/app/detail/components/AdEdit/components/TemplateList.tsx @@ -1,10 +1,9 @@ import React, { useMemo } from 'react'; import { Box, Flex } from '@chakra-ui/react'; import { ModuleTemplates } from '@/constants/flow/ModuleTemplate'; -import { FlowModuleTemplateType } from '@/types/flow'; +import { FlowModuleItemType, FlowModuleTemplateType } from '@/types/flow'; import type { Node, XYPosition } from 'reactflow'; import { useGlobalStore } from '@/store/global'; -import type { AppModuleItemType } from '@/types/app'; import Avatar from '@/components/Avatar'; import { FlowModuleTypeEnum } from '@/constants/flow'; @@ -14,7 +13,7 @@ const ModuleTemplateList = ({ onAddNode, onClose }: { - nodes?: Node[]; + nodes?: Node[]; isOpen: boolean; onAddNode: (e: { template: FlowModuleTemplateType; position: XYPosition }) => void; onClose: () => void; diff --git a/client/src/pages/app/detail/components/AdEdit/index.tsx b/client/src/pages/app/detail/components/AdEdit/index.tsx index cf0ac5531..97bc6a9c9 100644 --- a/client/src/pages/app/detail/components/AdEdit/index.tsx +++ b/client/src/pages/app/detail/components/AdEdit/index.tsx @@ -158,7 +158,9 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => { const flow2AppModules = useCallback(() => { const modules: AppModuleItemType[] = nodes.map((item) => ({ moduleId: item.data.moduleId, + name: item.data.name, flowType: item.data.flowType, + showStatus: item.data.showStatus, position: item.position, inputs: item.data.inputs.map((item) => ({ ...item, diff --git a/client/src/service/moduleDispatch/agent/extract.ts b/client/src/service/moduleDispatch/agent/extract.ts index 1fc3d6c30..11db8f3f7 100644 --- a/client/src/service/moduleDispatch/agent/extract.ts +++ b/client/src/service/moduleDispatch/agent/extract.ts @@ -34,6 +34,9 @@ export async function dispatchContentExtract({ history = [], description }: Props): Promise { + if (!content) { + return Promise.reject('Input is empty'); + } const messages: ChatItemType[] = [ ...history, { diff --git a/client/src/types/app.d.ts b/client/src/types/app.d.ts index f544f00b7..17be68bdb 100644 --- a/client/src/types/app.d.ts +++ b/client/src/types/app.d.ts @@ -69,9 +69,11 @@ export type VariableItemType = { /* app module */ export type AppModuleItemType = { + name: string; moduleId: string; position?: XYPosition; flowType: `${FlowModuleTypeEnum}`; + showStatus?: boolean; inputs: FlowInputItemType[]; outputs: FlowOutputItemType[]; }; @@ -83,8 +85,11 @@ export type AppItemType = { }; export type RunningModuleItemType = { - moduleId: string; - flowType: `${FlowModuleTypeEnum}`; + name: AppModuleItemType['name']; + moduleId: AppModuleItemType['moduleId']; + flowType: AppModuleItemType['flowType']; + showStatus?: AppModuleItemType['showStatus']; +} & { inputs: { key: string; value?: any; diff --git a/client/src/types/chat.d.ts b/client/src/types/chat.d.ts index af4d7e878..fbf02304d 100644 --- a/client/src/types/chat.d.ts +++ b/client/src/types/chat.d.ts @@ -13,7 +13,8 @@ export type ChatItemType = { }; export type ChatSiteItemType = { - status: 'loading' | 'finish'; + status: 'loading' | 'running' | 'finish'; + moduleName?: string; } & ChatItemType; export type HistoryItemType = { diff --git a/client/src/types/flow.d.ts b/client/src/types/flow.d.ts index c9ea19930..3cb39f3fa 100644 --- a/client/src/types/flow.d.ts +++ b/client/src/types/flow.d.ts @@ -55,6 +55,7 @@ export type FlowModuleTemplateType = { flowType: `${FlowModuleTypeEnum}`; inputs: FlowInputItemType[]; outputs: FlowOutputItemType[]; + showStatus?: boolean; }; export type FlowModuleItemType = FlowModuleTemplateType & { moduleId: string; diff --git a/client/src/utils/app.ts b/client/src/utils/app.ts index 996f2048a..a0c092cf4 100644 --- a/client/src/utils/app.ts +++ b/client/src/utils/app.ts @@ -219,6 +219,7 @@ const welcomeTemplate = (formData: EditFormType): AppModuleItemType[] => formData.guide?.welcome?.text ? [ { + name: '用户引导', flowType: FlowModuleTypeEnum.userGuide, inputs: [ { @@ -242,6 +243,7 @@ const variableTemplate = (formData: EditFormType): AppModuleItemType[] => formData.variables.length > 0 ? [ { + name: '全局变量', flowType: FlowModuleTypeEnum.variable, inputs: [ { @@ -263,6 +265,7 @@ const variableTemplate = (formData: EditFormType): AppModuleItemType[] => : []; const simpleChatTemplate = (formData: EditFormType): AppModuleItemType[] => [ { + name: '用户问题(对话入口)', flowType: FlowModuleTypeEnum.questionInput, inputs: [ { @@ -290,6 +293,7 @@ const simpleChatTemplate = (formData: EditFormType): AppModuleItemType[] => [ moduleId: 'userChatInput' }, { + name: '聊天记录', flowType: FlowModuleTypeEnum.historyNode, inputs: [ { @@ -324,6 +328,7 @@ const simpleChatTemplate = (formData: EditFormType): AppModuleItemType[] => [ moduleId: 'history' }, { + name: 'AI 对话', flowType: FlowModuleTypeEnum.chatNode, inputs: chatModelInput(formData), outputs: [ @@ -352,6 +357,7 @@ const simpleChatTemplate = (formData: EditFormType): AppModuleItemType[] => [ ]; const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [ { + name: '用户问题(对话入口)', flowType: FlowModuleTypeEnum.questionInput, inputs: [ { @@ -383,6 +389,7 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [ moduleId: 'userChatInput' }, { + name: '聊天记录', flowType: FlowModuleTypeEnum.historyNode, inputs: [ { @@ -417,6 +424,7 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [ moduleId: 'history' }, { + name: '知识库搜索', flowType: FlowModuleTypeEnum.kbSearchNode, inputs: [ { @@ -498,6 +506,7 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [ ...(formData.kb.searchEmptyText ? [ { + name: '指定回复', flowType: FlowModuleTypeEnum.answerNode, inputs: [ { @@ -525,6 +534,7 @@ const kbTemplate = (formData: EditFormType): AppModuleItemType[] => [ ] : []), { + name: 'AI 对话', flowType: FlowModuleTypeEnum.chatNode, inputs: chatModelInput(formData), outputs: [