@@ -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