Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
9a31407a
authored
Aug 04, 2023
by
archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: chat status
parent
c7bfd773
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
205 additions
and
46 deletions
+205
-46
client/public/locales/en/common.json
+1
-0
client/public/locales/zh/common.json
+1
-0
client/src/api/fetch.ts
+9
-2
client/src/components/ChatBox/index.module.scss
+13
-0
client/src/components/ChatBox/index.tsx
+57
-5
client/src/components/Markdown/index.tsx
+1
-1
client/src/constants/chat.ts
+2
-3
client/src/constants/flow/ModuleTemplate.ts
+58
-25
client/src/pages/api/openapi/v1/chat/completions.ts
+36
-4
client/src/pages/app/detail/components/AdEdit/components/TemplateList.tsx
+2
-3
client/src/pages/app/detail/components/AdEdit/index.tsx
+2
-0
client/src/service/moduleDispatch/agent/extract.ts
+3
-0
client/src/types/app.d.ts
+7
-2
client/src/types/chat.d.ts
+2
-1
client/src/types/flow.d.ts
+1
-0
client/src/utils/app.ts
+10
-0
No files found.
client/public/locales/en/common.json
View file @
9a31407a
...
...
@@ -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"
,
...
...
client/public/locales/zh/common.json
View file @
9a31407a
...
...
@@ -3,6 +3,7 @@
"Cancel"
:
"取消"
,
"Confirm"
:
"确认"
,
"Warning"
:
"提示"
,
"Running"
:
"运行中"
,
"app"
:
{
"App Detail"
:
"应用详情"
,
"Confirm Del App Tip"
:
"确认删除该应用及其所有聊天记录?"
,
...
...
client/src/api/fetch.ts
View file @
9a31407a
...
...
@@ -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
<
string
,
any
>
;
onMessage
:
(
text
:
string
)
=>
void
;
onMessage
:
StartChatFnProps
[
'generatingMessage'
]
;
abortSignal
:
AbortController
;
}
export
const
streamFetch
=
({
...
...
@@ -71,9 +72,15 @@ 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
)
)
{
...
...
client/src/components/ChatBox/index.module.scss
View file @
9a31407a
...
...
@@ -28,3 +28,16 @@
}
}
}
.statusAnimation
{
animation
:
statusBox
0
.8s
linear
infinite
alternate
;
}
@keyframes
statusBox
{
0
%
{
opacity
:
1
;
}
100
%
{
opacity
:
0
.11
;
}
}
client/src/components/ChatBox/index.tsx
View file @
9a31407a
...
...
@@ -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
<
string
,
any
>
;
generatingMessage
:
(
text
:
string
)
=>
void
;
generatingMessage
:
(
e
:
generatingMessageProps
)
=>
void
;
};
export
type
ComponentRef
=
{
...
...
@@ -153,6 +155,7 @@ const ChatBox = (
const
ChatBoxRef
=
useRef
<
HTMLDivElement
>
(
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
<
ChatSiteItemType
[]
>
([]);
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'
&&
(
<>
<
Flex
w=
{
'100%'
}
alignItems=
{
'
center
'
}
>
<
Flex
w=
{
'100%'
}
alignItems=
{
'
flex-end
'
}
>
<
ChatAvatar
src=
{
appAvatar
}
type=
{
'AI'
}
/>
<
Flex
{
...
controlContainerStyle
}
ml=
{
3
}
>
<
MyTooltip
label=
{
'复制'
}
>
...
...
@@ -635,6 +665,28 @@ const ChatBox = (
</
MyTooltip
>
)
}
</
Flex
>
{
statusBoxData
&&
index
===
chatHistory
.
length
-
1
&&
(
<
Flex
ml=
{
3
}
alignItems=
{
'center'
}
px=
{
3
}
py=
{
'1px'
}
borderRadius=
"md"
border=
{
theme
.
borders
.
base
}
>
<
Box
className=
{
styles
.
statusAnimation
}
bg=
{
statusBoxData
.
bg
}
w=
"8px"
h=
"8px"
borderRadius=
{
'50%'
}
mt=
{
'1px'
}
></
Box
>
<
Box
ml=
{
2
}
color=
{
'myGray.600'
}
>
{
statusBoxData
.
name
}
</
Box
>
</
Flex
>
)
}
</
Flex
>
<
Box
position=
{
'relative'
}
maxW=
{
messageCardMaxW
}
mt=
{
[
'6px'
,
2
]
}
>
<
Card
bg=
{
'white'
}
{
...
MessageCardStyle
}
>
...
...
client/src/components/Markdown/index.tsx
View file @
9a31407a
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'
;
...
...
client/src/constants/chat.ts
View file @
9a31407a
...
...
@@ -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
{
...
...
client/src/constants/flow/ModuleTemplate.ts
View file @
9a31407a
...
...
@@ -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: 160
1.023010865122
6
x:
464.32198615344566
,
y: 160
2.269846308160
6
},
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.85869410513
53
x:
1150.8317145593148
,
y:
957.96766728800
53
},
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:
2
000,
value:
8
000,
min: 100,
max:
4
000,
max:
16
000,
step: 50,
markList: [
{
...
...
@@ -624,8 +633,8 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] =
value: 100
},
{
label: '
4
000',
value:
4
000
label: '
16
000',
value:
16
000
}
],
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:
2
000,
value:
8
000,
min: 100,
max:
4
000,
max:
16
000,
step: 50,
markList: [
{
...
...
@@ -964,8 +980,8 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] =
value: 100
},
{
label: '
4
000',
value:
4
000
label: '
16
000',
value:
16
000
}
],
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:
2
000,
value:
8
000,
min: 100,
max:
4
000,
max:
16
000,
step: 50,
markList: [
{
...
...
@@ -1263,8 +1286,8 @@ export const appTemplates: (AppItemType & { avatar: string; intro: string })[] =
value: 100
},
{
label: '
4
000',
value:
4
000
label: '
16
000',
value:
16
000
}
],
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,
...
...
client/src/pages/api/openapi/v1/chat/completions.ts
View file @
9a31407a
...
...
@@ -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
<
string
,
any
>
=
{};
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
})
});
}
client/src/pages/app/detail/components/AdEdit/components/TemplateList.tsx
View file @
9a31407a
import
React
,
{
useMemo
}
from
'react'
;
import
{
Box
,
Flex
}
from
'@chakra-ui/react'
;
import
{
ModuleTemplates
}
from
'@/constants/flow/ModuleTemplate'
;
import
{
FlowModuleTemplateType
}
from
'@/types/flow'
;
import
{
FlowModule
ItemType
,
FlowModule
TemplateType
}
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
<
App
ModuleItemType
>
[];
nodes
?:
Node
<
Flow
ModuleItemType
>
[];
isOpen
:
boolean
;
onAddNode
:
(
e
:
{
template
:
FlowModuleTemplateType
;
position
:
XYPosition
})
=>
void
;
onClose
:
()
=>
void
;
...
...
client/src/pages/app/detail/components/AdEdit/index.tsx
View file @
9a31407a
...
...
@@ -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
,
...
...
client/src/service/moduleDispatch/agent/extract.ts
View file @
9a31407a
...
...
@@ -34,6 +34,9 @@ export async function dispatchContentExtract({
history
=
[],
description
}:
Props
):
Promise
<
Response
>
{
if
(
!
content
)
{
return
Promise
.
reject
(
'Input is empty'
);
}
const
messages
:
ChatItemType
[]
=
[
...
history
,
{
...
...
client/src/types/app.d.ts
View file @
9a31407a
...
...
@@ -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
;
...
...
client/src/types/chat.d.ts
View file @
9a31407a
...
...
@@ -13,7 +13,8 @@ export type ChatItemType = {
};
export
type
ChatSiteItemType
=
{
status
:
'loading'
|
'finish'
;
status
:
'loading'
|
'running'
|
'finish'
;
moduleName
?:
string
;
}
&
ChatItemType
;
export
type
HistoryItemType
=
{
...
...
client/src/types/flow.d.ts
View file @
9a31407a
...
...
@@ -55,6 +55,7 @@ export type FlowModuleTemplateType = {
flowType
:
`
${
FlowModuleTypeEnum
}
`
;
inputs
:
FlowInputItemType
[];
outputs
:
FlowOutputItemType
[];
showStatus
?:
boolean
;
};
export
type
FlowModuleItemType
=
FlowModuleTemplateType
&
{
moduleId
:
string
;
...
...
client/src/utils/app.ts
View file @
9a31407a
...
...
@@ -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
:
[
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment