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
3adb97b3
authored
Jul 25, 2023
by
archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: sse render
parent
6fc6c994
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
107 additions
and
99 deletions
+107
-99
client/src/api/fetch.ts
+12
-11
client/src/components/ChatBox/index.tsx
+3
-3
client/src/pages/app/list/component/CreateModal.tsx
+17
-27
client/src/service/moduleDispatch/chat/oneapi.ts
+19
-28
client/src/store/chat.ts
+1
-9
client/src/utils/adapt.ts
+0
-21
client/src/utils/sse.ts
+55
-0
No files found.
client/src/api/fetch.ts
View file @
3adb97b3
import
{
sseResponseEventEnum
,
TaskResponseKeyEnum
}
from
'@/constants/chat'
;
import
{
sseResponseEventEnum
,
TaskResponseKeyEnum
}
from
'@/constants/chat'
;
import
{
getErrText
}
from
'@/utils/tools'
;
import
{
getErrText
}
from
'@/utils/tools'
;
import
{
parseStreamChunk
}
from
'@/utils/adapt
'
;
import
{
parseStreamChunk
,
SSEParseData
}
from
'@/utils/sse
'
;
import
type
{
ChatHistoryItemResType
}
from
'@/types/chat'
;
import
type
{
ChatHistoryItemResType
}
from
'@/types/chat'
;
interface
StreamFetchProps
{
interface
StreamFetchProps
{
...
@@ -43,6 +43,8 @@ export const streamFetch = ({
...
@@ -43,6 +43,8 @@ export const streamFetch = ({
let
errMsg
=
''
;
let
errMsg
=
''
;
let
responseData
:
ChatHistoryItemResType
[]
=
[];
let
responseData
:
ChatHistoryItemResType
[]
=
[];
const
parseData
=
new
SSEParseData
();
const
read
=
async
()
=>
{
const
read
=
async
()
=>
{
try
{
try
{
const
{
done
,
value
}
=
await
reader
.
read
();
const
{
done
,
value
}
=
await
reader
.
read
();
...
@@ -63,21 +65,20 @@ export const streamFetch = ({
...
@@ -63,21 +65,20 @@ export const streamFetch = ({
chunkResponse
.
forEach
((
item
)
=>
{
chunkResponse
.
forEach
((
item
)
=>
{
// parse json data
// parse json data
const
data
=
(()
=>
{
const
{
eventName
,
data
}
=
parseData
.
parse
(
item
);
try
{
return
JSON
.
parse
(
item
.
data
);
if
(
!
eventName
||
!
data
)
return
;
}
catch
(
error
)
{
return
item
.
data
;
}
})();
if
(
item
.
event
===
sseResponseEventEnum
.
answer
&&
data
!==
'[DONE]'
)
{
if
(
eventName
===
sseResponseEventEnum
.
answer
&&
data
!==
'[DONE]'
)
{
const
answer
:
string
=
data
?.
choices
?.[
0
].
delta
.
content
||
''
;
const
answer
:
string
=
data
?.
choices
?.[
0
].
delta
.
content
||
''
;
onMessage
(
answer
);
onMessage
(
answer
);
responseText
+=
answer
;
responseText
+=
answer
;
}
else
if
(
item
.
event
===
sseResponseEventEnum
.
appStreamResponse
)
{
}
else
if
(
eventName
===
sseResponseEventEnum
.
appStreamResponse
&&
Array
.
isArray
(
data
)
)
{
responseData
=
data
;
responseData
=
data
;
}
else
if
(
item
.
event
===
sseResponseEventEnum
.
error
)
{
}
else
if
(
eventName
===
sseResponseEventEnum
.
error
)
{
errMsg
=
getErrText
(
data
,
'流响应错误'
);
errMsg
=
getErrText
(
data
,
'流响应错误'
);
}
}
});
});
...
...
client/src/components/ChatBox/index.tsx
View file @
3adb97b3
...
@@ -41,14 +41,14 @@ import { useGlobalStore } from '@/store/global';
...
@@ -41,14 +41,14 @@ import { useGlobalStore } from '@/store/global';
import
{
FlowModuleTypeEnum
}
from
'@/constants/flow'
;
import
{
FlowModuleTypeEnum
}
from
'@/constants/flow'
;
import
{
TaskResponseKeyEnum
}
from
'@/constants/chat'
;
import
{
TaskResponseKeyEnum
}
from
'@/constants/chat'
;
import
dynamic
from
'next/dynamic'
;
const
ResponseDetailModal
=
dynamic
(()
=>
import
(
'./ResponseDetailModal'
));
import
MyIcon
from
'@/components/Icon'
;
import
MyIcon
from
'@/components/Icon'
;
import
Avatar
from
'@/components/Avatar'
;
import
Avatar
from
'@/components/Avatar'
;
import
Markdown
from
'@/components/Markdown'
;
import
Markdown
from
'@/components/Markdown'
;
import
MySelect
from
'@/components/Select'
;
import
MySelect
from
'@/components/Select'
;
import
MyTooltip
from
'../MyTooltip'
;
import
MyTooltip
from
'../MyTooltip'
;
import
dynamic
from
'next/dynamic'
;
const
ResponseDetailModal
=
dynamic
(()
=>
import
(
'./ResponseDetailModal'
));
import
styles
from
'./index.module.scss'
;
import
styles
from
'./index.module.scss'
;
const
textareaMinH
=
'22px'
;
const
textareaMinH
=
'22px'
;
...
...
client/src/pages/app/list/component/CreateModal.tsx
View file @
3adb97b3
...
@@ -23,6 +23,7 @@ import { postCreateApp } from '@/api/app';
...
@@ -23,6 +23,7 @@ import { postCreateApp } from '@/api/app';
import
{
useRouter
}
from
'next/router'
;
import
{
useRouter
}
from
'next/router'
;
import
{
appTemplates
}
from
'@/constants/flow/ModuleTemplate'
;
import
{
appTemplates
}
from
'@/constants/flow/ModuleTemplate'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
{
useRequest
}
from
'@/hooks/useRequest'
;
import
Avatar
from
'@/components/Avatar'
;
import
Avatar
from
'@/components/Avatar'
;
import
MyTooltip
from
'@/components/MyTooltip'
;
import
MyTooltip
from
'@/components/MyTooltip'
;
...
@@ -34,7 +35,6 @@ type FormType = {
...
@@ -34,7 +35,6 @@ type FormType = {
const
CreateModal
=
({
onClose
,
onSuccess
}:
{
onClose
:
()
=>
void
;
onSuccess
:
()
=>
void
})
=>
{
const
CreateModal
=
({
onClose
,
onSuccess
}:
{
onClose
:
()
=>
void
;
onSuccess
:
()
=>
void
})
=>
{
const
[
refresh
,
setRefresh
]
=
useState
(
false
);
const
[
refresh
,
setRefresh
]
=
useState
(
false
);
const
[
creating
,
setCreating
]
=
useState
(
false
);
const
{
toast
}
=
useToast
();
const
{
toast
}
=
useToast
();
const
router
=
useRouter
();
const
router
=
useRouter
();
const
theme
=
useTheme
();
const
theme
=
useTheme
();
...
@@ -74,32 +74,22 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
...
@@ -74,32 +74,22 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
[
setValue
,
toast
]
[
setValue
,
toast
]
);
);
const
onclickCreate
=
useCallback
(
const
{
mutate
:
onclickCreate
,
isLoading
:
creating
}
=
useRequest
({
async
(
data
:
FormType
)
=>
{
mutationFn
:
async
(
data
:
FormType
)
=>
{
setCreating
(
true
);
return
postCreateApp
({
try
{
avatar
:
data
.
avatar
,
const
id
=
await
postCreateApp
({
name
:
data
.
name
,
avatar
:
data
.
avatar
,
modules
:
appTemplates
.
find
((
item
)
=>
item
.
id
===
data
.
templateId
)?.
modules
||
[]
name
:
data
.
name
,
});
modules
:
appTemplates
.
find
((
item
)
=>
item
.
id
===
data
.
templateId
)?.
modules
||
[]
});
toast
({
title
:
'创建成功'
,
status
:
'success'
});
router
.
push
(
`/app/detail?appId=
${
id
}
`
);
onClose
();
onSuccess
();
}
catch
(
error
)
{
toast
({
title
:
getErrText
(
error
,
'创建应用异常'
),
status
:
'error'
});
}
setCreating
(
false
);
},
},
[
onClose
,
onSuccess
,
router
,
toast
]
onSuccess
(
id
:
string
)
{
);
router
.
push
(
`/app/detail?appId=
${
id
}
`
);
onSuccess
();
onClose
();
},
successToast
:
'创建成功'
,
errorToast
:
'创建应用异常'
});
return
(
return
(
<
Modal
isOpen
onClose=
{
onClose
}
isCentered=
{
!
isPc
}
>
<
Modal
isOpen
onClose=
{
onClose
}
isCentered=
{
!
isPc
}
>
...
@@ -180,7 +170,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
...
@@ -180,7 +170,7 @@ const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: (
<
Button
variant=
{
'base'
}
mr=
{
3
}
onClick=
{
onClose
}
>
<
Button
variant=
{
'base'
}
mr=
{
3
}
onClick=
{
onClose
}
>
取消
取消
</
Button
>
</
Button
>
<
Button
isLoading=
{
creating
}
onClick=
{
handleSubmit
(
onclickCreate
)
}
>
<
Button
isLoading=
{
creating
}
onClick=
{
handleSubmit
(
(
data
)
=>
onclickCreate
(
data
)
)
}
>
确认创建
确认创建
</
Button
>
</
Button
>
</
ModalFooter
>
</
ModalFooter
>
...
...
client/src/service/moduleDispatch/chat/oneapi.ts
View file @
3adb97b3
...
@@ -7,7 +7,8 @@ import { ChatContextFilter } from '@/service/utils/chat/index';
...
@@ -7,7 +7,8 @@ import { ChatContextFilter } from '@/service/utils/chat/index';
import
type
{
ChatItemType
,
QuoteItemType
}
from
'@/types/chat'
;
import
type
{
ChatItemType
,
QuoteItemType
}
from
'@/types/chat'
;
import
type
{
ChatHistoryItemResType
}
from
'@/types/chat'
;
import
type
{
ChatHistoryItemResType
}
from
'@/types/chat'
;
import
{
ChatModuleEnum
,
ChatRoleEnum
,
sseResponseEventEnum
}
from
'@/constants/chat'
;
import
{
ChatModuleEnum
,
ChatRoleEnum
,
sseResponseEventEnum
}
from
'@/constants/chat'
;
import
{
parseStreamChunk
,
textAdaptGptResponse
}
from
'@/utils/adapt'
;
import
{
SSEParseData
,
parseStreamChunk
}
from
'@/utils/sse'
;
import
{
textAdaptGptResponse
}
from
'@/utils/adapt'
;
import
{
getOpenAIApi
,
axiosConfig
}
from
'@/service/ai/openai'
;
import
{
getOpenAIApi
,
axiosConfig
}
from
'@/service/ai/openai'
;
import
{
TaskResponseKeyEnum
}
from
'@/constants/chat'
;
import
{
TaskResponseKeyEnum
}
from
'@/constants/chat'
;
import
{
getChatModel
}
from
'@/service/utils/data'
;
import
{
getChatModel
}
from
'@/service/utils/data'
;
...
@@ -270,38 +271,28 @@ function getMaxTokens({
...
@@ -270,38 +271,28 @@ function getMaxTokens({
async
function
streamResponse
({
res
,
response
}:
{
res
:
NextApiResponse
;
response
:
any
})
{
async
function
streamResponse
({
res
,
response
}:
{
res
:
NextApiResponse
;
response
:
any
})
{
let
answer
=
''
;
let
answer
=
''
;
let
error
:
any
=
null
;
let
error
:
any
=
null
;
const
parseData
=
new
SSEParseData
();
const
clientRes
=
async
(
data
:
string
)
=>
{
const
{
content
=
''
}
=
(()
=>
{
try
{
const
json
=
JSON
.
parse
(
data
);
const
content
:
string
=
json
?.
choices
?.[
0
].
delta
.
content
||
''
;
error
=
json
.
error
;
answer
+=
content
;
return
{
content
};
}
catch
(
error
)
{
return
{};
}
})();
if
(
res
.
closed
||
error
)
return
;
if
(
data
!==
'[DONE]'
)
{
sseResponse
({
res
,
event
:
sseResponseEventEnum
.
answer
,
data
:
textAdaptGptResponse
({
text
:
content
})
});
}
};
try
{
try
{
for
await
(
const
chunk
of
response
.
data
as
any
)
{
for
await
(
const
chunk
of
response
.
data
as
any
)
{
if
(
res
.
closed
)
break
;
if
(
res
.
closed
)
break
;
const
parse
=
parseStreamChunk
(
chunk
);
const
parse
=
parseStreamChunk
(
chunk
);
parse
.
forEach
((
item
)
=>
clientRes
(
item
.
data
));
parse
.
forEach
((
item
)
=>
{
const
{
data
}
=
parseData
.
parse
(
item
);
if
(
!
data
||
data
===
'[DONE]'
)
return
;
const
content
:
string
=
data
?.
choices
?.[
0
].
delta
.
content
||
''
;
error
=
data
.
error
;
answer
+=
content
;
sseResponse
({
res
,
event
:
sseResponseEventEnum
.
answer
,
data
:
textAdaptGptResponse
({
text
:
content
})
});
});
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
log
(
'pipe error'
,
error
);
console
.
log
(
'pipe error'
,
error
);
...
...
client/src/store/chat.ts
View file @
3adb97b3
...
@@ -83,15 +83,7 @@ export const useChatStore = create<State>()(
...
@@ -83,15 +83,7 @@ export const useChatStore = create<State>()(
return
[
history
,
...
state
.
history
];
return
[
history
,
...
state
.
history
];
}
}
})();
})();
// newHistory.sort(function (a, b) {
// if (a.top === true && b.top === false) {
// return -1;
// } else if (a.top === false && b.top === true) {
// return 1;
// } else {
// return 0;
// }
// });
state
.
history
=
newHistory
;
state
.
history
=
newHistory
;
});
});
},
},
...
...
client/src/utils/adapt.ts
View file @
3adb97b3
...
@@ -60,27 +60,6 @@ export const textAdaptGptResponse = ({
...
@@ -60,27 +60,6 @@ export const textAdaptGptResponse = ({
});
});
};
};
const
decoder
=
new
TextDecoder
();
export
const
parseStreamChunk
=
(
value
:
BufferSource
)
=>
{
const
chunk
=
decoder
.
decode
(
value
);
const
chunkLines
=
chunk
.
split
(
'\n\n'
).
filter
((
item
)
=>
item
);
const
chunkResponse
=
chunkLines
.
map
((
item
)
=>
{
const
splitEvent
=
item
.
split
(
'\n'
);
if
(
splitEvent
.
length
===
2
)
{
return
{
event
:
splitEvent
[
0
].
replace
(
'event: '
,
''
),
data
:
splitEvent
[
1
].
replace
(
'data: '
,
''
)
};
}
return
{
event
:
''
,
data
:
splitEvent
[
0
].
replace
(
'data: '
,
''
)
};
});
return
chunkResponse
;
};
export
const
appModule2FlowNode
=
({
export
const
appModule2FlowNode
=
({
item
,
item
,
onChangeNode
,
onChangeNode
,
...
...
client/src/utils/sse.ts
0 → 100644
View file @
3adb97b3
const
decoder
=
new
TextDecoder
();
export
const
parseStreamChunk
=
(
value
:
BufferSource
)
=>
{
const
chunk
=
decoder
.
decode
(
value
);
const
chunkLines
=
chunk
.
split
(
'\n\n'
).
filter
((
item
)
=>
item
);
const
chunkResponse
=
chunkLines
.
map
((
item
)
=>
{
const
splitEvent
=
item
.
split
(
'\n'
);
if
(
splitEvent
.
length
===
2
)
{
return
{
event
:
splitEvent
[
0
].
replace
(
'event: '
,
''
),
data
:
splitEvent
[
1
].
replace
(
'data: '
,
''
)
};
}
return
{
event
:
''
,
data
:
splitEvent
[
0
].
replace
(
'data: '
,
''
)
};
});
return
chunkResponse
;
};
export
class
SSEParseData
{
storeReadData
=
''
;
storeEventName
=
''
;
parse
(
item
:
{
event
:
string
;
data
:
string
})
{
if
(
item
.
data
===
'[DONE]'
)
return
{
eventName
:
item
.
event
,
data
:
item
.
data
};
if
(
item
.
event
)
{
this
.
storeEventName
=
item
.
event
;
}
try
{
const
formatData
=
this
.
storeReadData
+
item
.
data
;
const
parseData
=
JSON
.
parse
(
formatData
);
const
eventName
=
this
.
storeEventName
;
this
.
storeReadData
=
''
;
this
.
storeEventName
=
''
;
return
{
eventName
,
data
:
parseData
};
}
catch
(
error
)
{
if
(
typeof
item
.
data
===
'string'
)
{
this
.
storeReadData
+=
item
.
data
;
}
else
{
this
.
storeReadData
=
''
;
}
}
return
{};
}
}
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