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
21ab8558
authored
Sep 26, 2024
by
Archer
Committed by
GitHub
Sep 26, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perf: stream response (#2813)
* perf: stream response * fold code
parent
aee5de29
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
66 additions
and
58 deletions
+66
-58
docSite/content/zh-cn/docs/development/upgrading/4811.md
+21
-20
packages/service/core/workflow/dispatch/interactive/formInput.ts
+3
-0
projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx
+8
-4
projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx
+6
-15
projects/app/src/web/common/api/fetch.ts
+27
-18
projects/app/src/web/core/chat/context/chatContext.tsx
+1
-1
No files found.
docSite/content/zh-cn/docs/development/upgrading/4811.md
View file @
21ab8558
...
@@ -84,24 +84,25 @@ weight: 813
...
@@ -84,24 +84,25 @@ weight: 813
## V4.8.11 更新说明
## V4.8.11 更新说明
1.
1.
新增 - 表单输入节点,允许用户在工作流中让用户输入一些信息。
2.
新增 - 循环运行节点,可传入数组进行批量调用,目前最多支持 50 长度的数组串行执行。
2.
新增 - 循环运行节点,可传入数组进行批量调用,目前最多支持 50 长度的数组串行执行。
3.
新增 - 聊天记录滚动加载,不再只加载 30 条。
3.
新增 - 节点支持折叠。
4.
新增 - 工作流增加触摸板优先模式。
4.
新增 - 聊天记录滚动加载,不再只加载 30 条。
5.
新增 - 沙盒增加字符串转 base64 全局方法。
5.
新增 - 工作流增加触摸板优先模式,可以通过工作流右下角按键进行切换。
6.
新增 - 支持 Openai o1 模型,需增加模型的
`defaultConfig`
配置,覆盖
`temperature`
、
`max_tokens`
和
`stream`
配置,o1 不支持 stream 模式, 详细可重新拉取
`config.json`
配置文件查看。
6.
新增 - 沙盒增加字符串转 base64 全局方法(全局变量 strToBase64)。
7.
新增 - AI 对话节点知识库引用,支持配置 role=system 和 role=user,已配置的过自定义提示词的节点将会保持 user 模式,其余用户将转成 system 模式。
7.
新增 - 支持 Openai o1 模型,需增加模型的
`defaultConfig`
配置,覆盖
`temperature`
、
`max_tokens`
和
`stream`
配置,o1 不支持 stream 模式, 详细可重新拉取
`config.json`
配置文件查看。
8.
新增 - 插件支持上传系统文件。
8.
新增 - AI 对话节点知识库引用,支持配置 role=system 和 role=user,已配置的过自定义提示词的节点将会保持 user 模式,其余用户将转成 system 模式。
9.
新增 - 插件输出,支持指定字段作为工具响应。
9.
新增 - 插件支持上传系统文件。
10.
新增 - 支持工作流嵌套子应用时,可以设置
`非流模式`
,同时简易模式也可以选择工作流作为插件了,简易模式调用子应用时,都将强制使用非流模式。
10.
新增 - 插件输出,支持指定字段作为工具响应。
11.
新增 - 调试模式下,子应用调用,支持返回详细运行数据。
11.
新增 - 支持工作流嵌套子应用时,可以设置
`非流模式`
,同时简易模式也可以选择工作流作为插件了,简易模式调用子应用时,都将强制使用非流模式。
12.
新增 - 保留所有模式下子应用嵌套调用的日志。
12.
新增 - 调试模式下,子应用调用,支持返回详细运行数据。
13.
优化 - 工作流嵌套层级限制 20 层,避免因编排不合理导致的无限死循环。
13.
新增 - 保留所有模式下子应用嵌套调用的日志。
14.
优化 - 工作流 handler 性能优化。
14.
优化 - 工作流嵌套层级限制 20 层,避免因编排不合理导致的无限死循环。
15.
优化 - 工作流快捷键,避免调试测试时也会触发。
15.
优化 - 工作流 handler 性能优化。
16.
优化 - 流输出,切换 tab 时仍可以继续输出。
16.
优化 - 工作流快捷键,避免调试测试时也会触发复制和回退。
17.
优化 - 完善外部文件知识库相关 API
17.
优化 - 流输出,切换浏览器 Tab 后仍可以继续输出。
18.
修复 - 知识库选择权限问题。
18.
优化 - 完善外部文件知识库相关 API
19.
修复 - 空 chatId 发起对话,首轮携带用户选择时会异常。
19.
修复 - 知识库选择权限问题。
20.
修复 - createDataset 接口,intro 为赋值。
20.
修复 - 空 chatId 发起对话,首轮携带用户选择时会异常。
21.
修复 - 对话框渲染性能问题。
21.
修复 - createDataset 接口,intro 为赋值。
22.
修复 - 对话框渲染性能问题。
packages/service/core/workflow/dispatch/interactive/formInput.ts
View file @
21ab8558
...
@@ -20,6 +20,9 @@ type FormInputResponse = DispatchNodeResultType<{
...
@@ -20,6 +20,9 @@ type FormInputResponse = DispatchNodeResultType<{
[
NodeOutputKeyEnum
.
formInputResult
]?:
Record
<
string
,
any
>
;
[
NodeOutputKeyEnum
.
formInputResult
]?:
Record
<
string
,
any
>
;
}
>
;
}
>
;
/*
用户输入都内容,将会以 JSON 字符串格式进入工作流,可以从 query 的 text 中获取。
*/
export
const
dispatchFormInput
=
async
(
props
:
Props
):
Promise
<
FormInputResponse
>
=>
{
export
const
dispatchFormInput
=
async
(
props
:
Props
):
Promise
<
FormInputResponse
>
=>
{
const
{
const
{
histories
,
histories
,
...
...
projects/app/src/components/core/chat/ChatContainer/ChatBox/index.tsx
View file @
21ab8558
...
@@ -199,13 +199,15 @@ const ChatBox = (
...
@@ -199,13 +199,15 @@ const ChatBox = (
// 聊天信息生成中……获取当前滚动条位置,判断是否需要滚动到底部
// 聊天信息生成中……获取当前滚动条位置,判断是否需要滚动到底部
const
{
run
:
generatingScroll
}
=
useThrottleFn
(
const
{
run
:
generatingScroll
}
=
useThrottleFn
(
()
=>
{
(
force
?:
boolean
)
=>
{
if
(
!
ChatBoxRef
.
current
)
return
;
if
(
!
ChatBoxRef
.
current
)
return
;
const
isBottom
=
const
isBottom
=
ChatBoxRef
.
current
.
scrollTop
+
ChatBoxRef
.
current
.
clientHeight
+
150
>=
ChatBoxRef
.
current
.
scrollTop
+
ChatBoxRef
.
current
.
clientHeight
+
150
>=
ChatBoxRef
.
current
.
scrollHeight
;
ChatBoxRef
.
current
.
scrollHeight
;
isBottom
&&
scrollToBottom
(
'auto'
);
if
(
isBottom
||
force
)
{
scrollToBottom
(
'auto'
);
}
},
},
{
{
wait
:
100
wait
:
100
...
@@ -321,7 +323,9 @@ const ChatBox = (
...
@@ -321,7 +323,9 @@ const ChatBox = (
return
item
;
return
item
;
})
})
);
);
generatingScroll
();
const
forceScroll
=
event
===
SseResponseEventEnum
.
interactive
;
generatingScroll
(
forceScroll
);
}
}
);
);
...
@@ -529,7 +533,7 @@ const ChatBox = (
...
@@ -529,7 +533,7 @@ const ChatBox = (
});
});
}
}
generatingScroll
();
generatingScroll
(
true
);
isPc
&&
TextareaDom
.
current
?.
focus
();
isPc
&&
TextareaDom
.
current
?.
focus
();
},
100
);
},
100
);
...
...
projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx
View file @
21ab8558
...
@@ -180,21 +180,12 @@ const NodeCard = (props: Props) => {
...
@@ -180,21 +180,12 @@ const NodeCard = (props: Props) => {
});
});
}
}
}
}
>
>
{
!
isFolded
?
(
<
MyIcon
<
MyIcon
name=
{
isFolded
?
'core/chat/chevronDown'
:
'core/chat/chevronRight'
}
name=
{
'core/chat/chevronDown'
}
w=
{
'24px'
}
w=
{
'24px'
}
h=
{
'24px'
}
h=
{
'24px'
}
color=
{
'myGray.500'
}
color=
{
'myGray.500'
}
/>
/>
)
:
(
<
MyIcon
name=
{
'core/chat/chevronRight'
}
w=
{
'24px'
}
h=
{
'24px'
}
color=
{
'myGray.500'
}
/>
)
}
</
Box
>
</
Box
>
)
}
)
}
<
Avatar
src=
{
avatar
}
borderRadius=
{
'sm'
}
objectFit=
{
'contain'
}
w=
{
'30px'
}
h=
{
'30px'
}
/>
<
Avatar
src=
{
avatar
}
borderRadius=
{
'sm'
}
objectFit=
{
'contain'
}
w=
{
'30px'
}
h=
{
'30px'
}
/>
...
...
projects/app/src/web/common/api/fetch.ts
View file @
21ab8558
...
@@ -22,6 +22,16 @@ export type StreamResponseType = {
...
@@ -22,6 +22,16 @@ export type StreamResponseType = {
responseText
:
string
;
responseText
:
string
;
[
DispatchNodeResponseKeyEnum
.
nodeResponse
]:
ChatHistoryItemResType
[];
[
DispatchNodeResponseKeyEnum
.
nodeResponse
]:
ChatHistoryItemResType
[];
};
};
type
ResponseQueueItemType
=
|
{
event
:
SseResponseEventEnum
.
fastAnswer
|
SseResponseEventEnum
.
answer
;
text
:
string
}
|
{
event
:
SseResponseEventEnum
.
interactive
;
[
key
:
string
]:
any
}
|
{
event
:
|
SseResponseEventEnum
.
toolCall
|
SseResponseEventEnum
.
toolParams
|
SseResponseEventEnum
.
toolResponse
;
[
key
:
string
]:
any
;
};
class
FatalError
extends
Error
{}
class
FatalError
extends
Error
{}
export
const
streamFetch
=
({
export
const
streamFetch
=
({
...
@@ -31,22 +41,14 @@ export const streamFetch = ({
...
@@ -31,22 +41,14 @@ export const streamFetch = ({
abortCtrl
abortCtrl
}:
StreamFetchProps
)
=>
}:
StreamFetchProps
)
=>
new
Promise
<
StreamResponseType
>
(
async
(
resolve
,
reject
)
=>
{
new
Promise
<
StreamResponseType
>
(
async
(
resolve
,
reject
)
=>
{
// First res
const
timeoutId
=
setTimeout
(()
=>
{
const
timeoutId
=
setTimeout
(()
=>
{
abortCtrl
.
abort
(
'Time out'
);
abortCtrl
.
abort
(
'Time out'
);
},
60000
);
},
60000
);
// response data
// response data
let
responseText
=
''
;
let
responseText
=
''
;
let
responseQueue
:
(
let
responseQueue
:
ResponseQueueItemType
[]
=
[];
|
{
event
:
SseResponseEventEnum
.
fastAnswer
|
SseResponseEventEnum
.
answer
;
text
:
string
}
|
{
event
:
|
SseResponseEventEnum
.
toolCall
|
SseResponseEventEnum
.
toolParams
|
SseResponseEventEnum
.
toolResponse
;
[
key
:
string
]:
any
;
}
)[]
=
[];
let
errMsg
:
string
|
undefined
;
let
errMsg
:
string
|
undefined
;
let
responseData
:
ChatHistoryItemResType
[]
=
[];
let
responseData
:
ChatHistoryItemResType
[]
=
[];
let
finished
=
false
;
let
finished
=
false
;
...
@@ -84,7 +86,7 @@ export const streamFetch = ({
...
@@ -84,7 +86,7 @@ export const streamFetch = ({
}
}
if
(
responseQueue
.
length
>
0
)
{
if
(
responseQueue
.
length
>
0
)
{
const
fetchCount
=
Math
.
max
(
1
,
Math
.
round
(
responseQueue
.
length
/
2
0
));
const
fetchCount
=
Math
.
max
(
1
,
Math
.
round
(
responseQueue
.
length
/
3
0
));
for
(
let
i
=
0
;
i
<
fetchCount
;
i
++
)
{
for
(
let
i
=
0
;
i
<
fetchCount
;
i
++
)
{
const
item
=
responseQueue
[
i
];
const
item
=
responseQueue
[
i
];
onMessage
(
item
);
onMessage
(
item
);
...
@@ -100,13 +102,20 @@ export const streamFetch = ({
...
@@ -100,13 +102,20 @@ export const streamFetch = ({
return
finish
();
return
finish
();
}
}
document
.
hidden
requestAnimationFrame
(
animateResponseText
);
?
setTimeout
(
animateResponseText
,
16
)
:
requestAnimationFrame
(
animateResponseText
);
}
}
// start animation
// start animation
animateResponseText
();
animateResponseText
();
const
pushDataToQueue
=
(
data
:
ResponseQueueItemType
)
=>
{
// If the document is hidden, the data is directly sent to the front end
responseQueue
.
push
(
data
);
if
(
document
.
hidden
)
{
animateResponseText
();
}
};
try
{
try
{
// auto complete variables
// auto complete variables
const
variables
=
data
?.
variables
||
{};
const
variables
=
data
?.
variables
||
{};
...
@@ -171,14 +180,14 @@ export const streamFetch = ({
...
@@ -171,14 +180,14 @@ export const streamFetch = ({
if
(
event
===
SseResponseEventEnum
.
answer
)
{
if
(
event
===
SseResponseEventEnum
.
answer
)
{
const
text
=
parseJson
.
choices
?.[
0
]?.
delta
?.
content
||
''
;
const
text
=
parseJson
.
choices
?.[
0
]?.
delta
?.
content
||
''
;
for
(
const
item
of
text
)
{
for
(
const
item
of
text
)
{
responseQueue
.
push
({
pushDataToQueue
({
event
,
event
,
text
:
item
text
:
item
});
});
}
}
}
else
if
(
event
===
SseResponseEventEnum
.
fastAnswer
)
{
}
else
if
(
event
===
SseResponseEventEnum
.
fastAnswer
)
{
const
text
=
parseJson
.
choices
?.[
0
]?.
delta
?.
content
||
''
;
const
text
=
parseJson
.
choices
?.[
0
]?.
delta
?.
content
||
''
;
responseQueue
.
push
({
pushDataToQueue
({
event
,
event
,
text
text
});
});
...
@@ -187,7 +196,7 @@ export const streamFetch = ({
...
@@ -187,7 +196,7 @@ export const streamFetch = ({
event
===
SseResponseEventEnum
.
toolParams
||
event
===
SseResponseEventEnum
.
toolParams
||
event
===
SseResponseEventEnum
.
toolResponse
event
===
SseResponseEventEnum
.
toolResponse
)
{
)
{
responseQueue
.
push
({
pushDataToQueue
({
event
,
event
,
...
parseJson
...
parseJson
});
});
...
@@ -204,7 +213,7 @@ export const streamFetch = ({
...
@@ -204,7 +213,7 @@ export const streamFetch = ({
variables
:
parseJson
variables
:
parseJson
});
});
}
else
if
(
event
===
SseResponseEventEnum
.
interactive
)
{
}
else
if
(
event
===
SseResponseEventEnum
.
interactive
)
{
responseQueue
.
push
({
pushDataToQueue
({
event
,
event
,
...
parseJson
...
parseJson
});
});
...
...
projects/app/src/web/core/chat/context/chatContext.tsx
View file @
21ab8558
...
@@ -200,7 +200,7 @@ const ChatContextProvider = ({
...
@@ -200,7 +200,7 @@ const ChatContextProvider = ({
);
);
}
else
{
}
else
{
// Chat history not exists
// Chat history not exists
loadHistories
();
loadHistories
(
true
);
}
}
},
},
[
histories
,
loadHistories
,
setHistories
]
[
histories
,
loadHistories
,
setHistories
]
...
...
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