feat: add typing effect (#1017)

* feat: add typing effect

* fix: ts2339 xxx not exist on type 'never'

---------

Co-authored-by: WangYi <wangyi@windimg.com>
This commit is contained in:
puppywang 2023-03-31 11:50:32 +08:00 committed by GitHub
parent 468bed7705
commit c0f4af05e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 15 deletions

View File

@ -25,7 +25,7 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
try { try {
const { prompt, options = {}, systemMessage } = req.body as RequestProps const { prompt, options = {}, systemMessage } = req.body as RequestProps
let firstChunk = true let firstChunk = true
await chatReplyProcess({ const finalResponse = await chatReplyProcess({
message: prompt, message: prompt,
lastContext: options, lastContext: options,
process: (chat: ChatMessage) => { process: (chat: ChatMessage) => {
@ -34,6 +34,7 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
}, },
systemMessage, systemMessage,
}) })
res.write(firstChunk ? JSON.stringify(finalResponse) : `\n${JSON.stringify(finalResponse)}`)
} }
catch (error) { catch (error) {
res.write(JSON.stringify(error)) res.write(JSON.stringify(error))

View File

@ -25,6 +25,12 @@ function http<T = any>(
const successHandler = (res: AxiosResponse<Response<T>>) => { const successHandler = (res: AxiosResponse<Response<T>>) => {
const authStore = useAuthStore() const authStore = useAuthStore()
if (typeof res.data === 'string') {
const lastIndex = (res.data as string).lastIndexOf('\n')
if (lastIndex !== -1)
res.data = JSON.parse((res.data as string).substring(lastIndex))
}
if (res.data.status === 'Success' || typeof res.data === 'string') if (res.data.status === 'Success' || typeof res.data === 'string')
return res.data return res.data

View File

@ -65,19 +65,17 @@ defineExpose({ textRef })
<template> <template>
<div class="text-black" :class="wrapClass"> <div class="text-black" :class="wrapClass">
<template v-if="loading">
<span class="dark:text-white w-[4px] h-[20px] block animate-blink" />
</template>
<template v-else>
<div ref="textRef" class="leading-relaxed break-words"> <div ref="textRef" class="leading-relaxed break-words">
<div v-if="!inversion"> <div v-if="!inversion">
<div v-if="!asRawText" class="markdown-body" v-html="text" /> <div v-if="!asRawText" class="markdown-body" v-html="text" />
<div v-else class="whitespace-pre-wrap" v-text="text" /> <div v-else class="whitespace-pre-wrap" v-text="text" />
</div> </div>
<div v-else class="whitespace-pre-wrap" v-text="text" /> <div v-else class="whitespace-pre-wrap" v-text="text" />
</div> <template v-if="loading">
<span class="dark:text-white w-[4px] h-[20px] block animate-blink" />
</template> </template>
</div> </div>
</div>
</template> </template>
<style lang="less"> <style lang="less">

View File

@ -109,7 +109,7 @@ async function onConversation() {
try { try {
let lastText = '' let lastText = ''
const fetchChatAPIOnce = async () => { const fetchChatAPIOnce = async () => {
await fetchChatAPIProcess<Chat.ConversationResponse>({ const { data } = await fetchChatAPIProcess<Chat.ConversationResponse>({
prompt: message, prompt: message,
options, options,
signal: controller.signal, signal: controller.signal,
@ -131,7 +131,7 @@ async function onConversation() {
text: lastText + data.text ?? '', text: lastText + data.text ?? '',
inversion: false, inversion: false,
error: false, error: false,
loading: false, loading: true,
conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id }, conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
requestOptions: { prompt: message, options: { ...options } }, requestOptions: { prompt: message, options: { ...options } },
}, },
@ -151,6 +151,19 @@ async function onConversation() {
} }
}, },
}) })
updateChat(
+uuid,
dataSources.value.length - 1,
{
dateTime: new Date().toLocaleString(),
text: lastText + data.text ?? '',
inversion: false,
error: false,
loading: false,
conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
requestOptions: { prompt: message, options: { ...options } },
},
)
} }
await fetchChatAPIOnce() await fetchChatAPIOnce()
@ -239,7 +252,7 @@ async function onRegenerate(index: number) {
try { try {
let lastText = '' let lastText = ''
const fetchChatAPIOnce = async () => { const fetchChatAPIOnce = async () => {
await fetchChatAPIProcess<Chat.ConversationResponse>({ const { data } = await fetchChatAPIProcess<Chat.ConversationResponse>({
prompt: message, prompt: message,
options, options,
signal: controller.signal, signal: controller.signal,
@ -261,7 +274,7 @@ async function onRegenerate(index: number) {
text: lastText + data.text ?? '', text: lastText + data.text ?? '',
inversion: false, inversion: false,
error: false, error: false,
loading: false, loading: true,
conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id }, conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
requestOptions: { prompt: message, ...options }, requestOptions: { prompt: message, ...options },
}, },
@ -279,6 +292,19 @@ async function onRegenerate(index: number) {
} }
}, },
}) })
updateChat(
+uuid,
index,
{
dateTime: new Date().toLocaleString(),
text: lastText + data.text ?? '',
inversion: false,
error: false,
loading: false,
conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
requestOptions: { prompt: message, ...options },
},
)
} }
await fetchChatAPIOnce() await fetchChatAPIOnce()
} }