Skip to content

Commit 78bcf7f

Browse files
perf: optimized output (#962)
* Update index.ts * Update index.vue * Update index.ts
1 parent c0a9fd5 commit 78bcf7f

File tree

2 files changed

+101
-90
lines changed

2 files changed

+101
-90
lines changed

service/src/index.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,21 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
2525
try {
2626
const { prompt, options = {}, systemMessage } = req.body as RequestProps
2727
let firstChunk = true
28+
let chatLength = 0
29+
let newChatLength = 0
2830
await chatReplyProcess({
2931
message: prompt,
3032
lastContext: options,
3133
process: (chat: ChatMessage) => {
32-
res.write(firstChunk ? JSON.stringify(chat) : `\n${JSON.stringify(chat)}`)
33-
firstChunk = false
34+
if (firstChunk) {
35+
res.write(`${JSON.stringify(chat)}t1h1i4s5i1s4a1s9i1l9l8y1s0plit`)
36+
firstChunk = false
37+
}
38+
else if (chatLength !== chat.text.length) {
39+
newChatLength = chat.text.length
40+
res.write(chat.text.substring(chatLength, newChatLength))
41+
chatLength = newChatLength
42+
}
3443
},
3544
systemMessage,
3645
})

src/views/chat/index.vue

Lines changed: 90 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ async function onConversation() {
107107
scrollToBottom()
108108
109109
try {
110-
let lastText = ''
110+
const magicSplit = 't1h1i4s5i1s4a1s9i1l9l8y1s0plit'
111+
let renderText = ''
112+
let firstTime = true
111113
const fetchChatAPIOnce = async () => {
112114
await fetchChatAPIProcess<Chat.ConversationResponse>({
113115
prompt: message,
@@ -117,42 +119,49 @@ async function onConversation() {
117119
const xhr = event.target
118120
const { responseText } = xhr
119121
// Always process the final line
120-
const lastIndex = responseText.lastIndexOf('\n', responseText.length - 2)
121-
let chunk = responseText
122-
if (lastIndex !== -1)
123-
chunk = responseText.substring(lastIndex)
124-
try {
125-
const data = JSON.parse(chunk)
126-
updateChat(
127-
+uuid,
128-
dataSources.value.length - 1,
129-
{
130-
dateTime: new Date().toLocaleString(),
131-
text: lastText + data.text ?? '',
132-
inversion: false,
133-
error: false,
134-
loading: false,
135-
conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
136-
requestOptions: { prompt: message, options: { ...options } },
137-
},
138-
)
139-
140-
if (openLongReply && data.detail.choices[0].finish_reason === 'length') {
141-
options.parentMessageId = data.id
142-
lastText = data.text
143-
message = ''
144-
return fetchChatAPIOnce()
145-
}
146122
147-
scrollToBottomIfAtBottom()
148-
}
149-
catch (error) {
150-
//
123+
const splitIndexBegin = responseText.search(magicSplit)
124+
if (splitIndexBegin !== -1) {
125+
const splitIndexEnd = splitIndexBegin + magicSplit.length
126+
127+
const firstChunk = responseText.substring(0, splitIndexBegin)
128+
const deltaText = responseText.substring(splitIndexEnd)
129+
try {
130+
const data = JSON.parse(firstChunk)
131+
if (firstTime) {
132+
firstTime = false
133+
renderText = data.text ?? ''
134+
}
135+
else {
136+
renderText = deltaText ?? ''
137+
}
138+
updateChat(
139+
+uuid,
140+
dataSources.value.length - 1,
141+
{
142+
dateTime: new Date().toLocaleString(),
143+
text: renderText,
144+
inversion: false,
145+
error: false,
146+
loading: false,
147+
conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
148+
requestOptions: { prompt: message, ...options },
149+
},
150+
)
151+
152+
if (openLongReply && data.detail.choices[0].finish_reason === 'length') {
153+
options.parentMessageId = data.id
154+
message = ''
155+
return fetchChatAPIOnce()
156+
}
157+
}
158+
catch (error) {
159+
//
160+
}
151161
}
152162
},
153163
})
154164
}
155-
156165
await fetchChatAPIOnce()
157166
}
158167
catch (error: any) {
@@ -237,7 +246,9 @@ async function onRegenerate(index: number) {
237246
)
238247
239248
try {
240-
let lastText = ''
249+
const magicSplit = 't1h1i4s5i1s4a1s9i1l9l8y1s0plit'
250+
let renderText = ''
251+
let firstTime = true
241252
const fetchChatAPIOnce = async () => {
242253
await fetchChatAPIProcess<Chat.ConversationResponse>({
243254
prompt: message,
@@ -247,35 +258,45 @@ async function onRegenerate(index: number) {
247258
const xhr = event.target
248259
const { responseText } = xhr
249260
// Always process the final line
250-
const lastIndex = responseText.lastIndexOf('\n', responseText.length - 2)
251-
let chunk = responseText
252-
if (lastIndex !== -1)
253-
chunk = responseText.substring(lastIndex)
254-
try {
255-
const data = JSON.parse(chunk)
256-
updateChat(
257-
+uuid,
258-
index,
259-
{
260-
dateTime: new Date().toLocaleString(),
261-
text: lastText + data.text ?? '',
262-
inversion: false,
263-
error: false,
264-
loading: false,
265-
conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
266-
requestOptions: { prompt: message, ...options },
267-
},
268-
)
269-
270-
if (openLongReply && data.detail.choices[0].finish_reason === 'length') {
271-
options.parentMessageId = data.id
272-
lastText = data.text
273-
message = ''
274-
return fetchChatAPIOnce()
261+
262+
const splitIndexBegin = responseText.search(magicSplit)
263+
if (splitIndexBegin !== -1) {
264+
const splitIndexEnd = splitIndexBegin + magicSplit.length
265+
266+
const firstChunk = responseText.substring(0, splitIndexBegin)
267+
const deltaText = responseText.substring(splitIndexEnd)
268+
try {
269+
const data = JSON.parse(firstChunk)
270+
if (firstTime) {
271+
firstTime = false
272+
renderText = data.text ?? ''
273+
}
274+
else {
275+
renderText = deltaText ?? ''
276+
}
277+
updateChat(
278+
+uuid,
279+
index,
280+
{
281+
dateTime: new Date().toLocaleString(),
282+
text: renderText,
283+
inversion: false,
284+
error: false,
285+
loading: false,
286+
conversationOptions: { conversationId: data.conversationId, parentMessageId: data.id },
287+
requestOptions: { prompt: message, ...options },
288+
},
289+
)
290+
291+
if (openLongReply && data.detail.choices[0].finish_reason === 'length') {
292+
options.parentMessageId = data.id
293+
message = ''
294+
return fetchChatAPIOnce()
295+
}
296+
}
297+
catch (error) {
298+
//
275299
}
276-
}
277-
catch (error) {
278-
//
279300
}
280301
},
281302
})
@@ -467,20 +488,13 @@ onUnmounted(() => {
467488
<template>
468489
<div class="flex flex-col w-full h-full">
469490
<HeaderComponent
470-
v-if="isMobile"
471-
:using-context="usingContext"
472-
@export="handleExport"
491+
v-if="isMobile" :using-context="usingContext" @export="handleExport"
473492
@toggle-using-context="toggleUsingContext"
474493
/>
475494
<main class="flex-1 overflow-hidden">
476-
<div
477-
id="scrollRef"
478-
ref="scrollRef"
479-
class="h-full overflow-hidden overflow-y-auto"
480-
>
495+
<div id="scrollRef" ref="scrollRef" class="h-full overflow-hidden overflow-y-auto">
481496
<div
482-
id="image-wrapper"
483-
class="w-full max-w-screen-xl m-auto dark:bg-[#101014]"
497+
id="image-wrapper" class="w-full max-w-screen-xl m-auto dark:bg-[#101014]"
484498
:class="[isMobile ? 'p-2' : 'p-4']"
485499
>
486500
<template v-if="!dataSources.length">
@@ -492,14 +506,8 @@ onUnmounted(() => {
492506
<template v-else>
493507
<div>
494508
<Message
495-
v-for="(item, index) of dataSources"
496-
:key="index"
497-
:date-time="item.dateTime"
498-
:text="item.text"
499-
:inversion="item.inversion"
500-
:error="item.error"
501-
:loading="item.loading"
502-
@regenerate="onRegenerate(index)"
509+
v-for="(item, index) of dataSources" :key="index" :date-time="item.dateTime" :text="item.text"
510+
:inversion="item.inversion" :error="item.error" :loading="item.loading" @regenerate="onRegenerate(index)"
503511
@delete="handleDelete(index)"
504512
/>
505513
<div class="sticky bottom-0 left-0 flex justify-center">
@@ -536,15 +544,9 @@ onUnmounted(() => {
536544
<NAutoComplete v-model:value="prompt" :options="searchOptions" :render-label="renderOption">
537545
<template #default="{ handleInput, handleBlur, handleFocus }">
538546
<NInput
539-
ref="inputRef"
540-
v-model:value="prompt"
541-
type="textarea"
542-
:placeholder="placeholder"
543-
:autosize="{ minRows: 1, maxRows: isMobile ? 4 : 8 }"
544-
@input="handleInput"
545-
@focus="handleFocus"
546-
@blur="handleBlur"
547-
@keypress="handleEnter"
547+
ref="inputRef" v-model:value="prompt" type="textarea" :placeholder="placeholder"
548+
:autosize="{ minRows: 1, maxRows: isMobile ? 4 : 8 }" @input="handleInput" @focus="handleFocus"
549+
@blur="handleBlur" @keypress="handleEnter"
548550
/>
549551
</template>
550552
</NAutoComplete>

0 commit comments

Comments
 (0)