@@ -225,7 +225,12 @@ router.post('/chat-clear', auth, async (req, res) => {
225225} )
226226
227227router . post ( '/chat-process' , [ auth , limiter ] , async ( req , res ) => {
228- res . setHeader ( 'Content-type' , 'application/octet-stream' )
228+ // set headers for SSE
229+ res . setHeader ( 'Content-Type' , 'text/event-stream' )
230+ res . setHeader ( 'Cache-Control' , 'no-cache' )
231+ res . setHeader ( 'Connection' , 'keep-alive' )
232+ res . setHeader ( 'Access-Control-Allow-Origin' , '*' )
233+ res . setHeader ( 'Access-Control-Allow-Headers' , 'Cache-Control' )
229234
230235 let { roomId, uuid, regenerate, prompt, uploadFileKeys, options = { } , systemMessage, temperature, top_p } = req . body as RequestProps
231236 const userId = req . headers . userId . toString ( )
@@ -241,6 +246,22 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
241246 let result
242247 let message : ChatInfo
243248 let user = await getUserById ( userId )
249+
250+ // SSE helper functions
251+ const sendSSEData = ( eventType : string , data : any ) => {
252+ res . write ( `event: ${ eventType } \n` )
253+ res . write ( `data: ${ JSON . stringify ( data ) } \n\n` )
254+ }
255+
256+ const sendSSEError = ( error : string ) => {
257+ sendSSEData ( 'error' , JSON . stringify ( { message : error } ) )
258+ }
259+
260+ const sendSSEEnd = ( ) => {
261+ res . write ( 'event: end\n' )
262+ res . write ( 'data: [DONE]\n\n' )
263+ }
264+
244265 try {
245266 // If use the fixed fakeuserid(some probability of duplicated with real ones), redefine user which is send to chatReplyProcess
246267 if ( userId === '6406d8c50aedd633885fa16f' ) {
@@ -251,29 +272,56 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
251272 if ( config . siteConfig ?. usageCountLimit ) {
252273 const useAmount = user ? ( user . useAmount ?? 0 ) : 0
253274 if ( Number ( useAmount ) <= 0 && user . limit_switch ) {
254- res . send ( { status : 'Fail' , message : '提问次数用完啦 | Question limit reached' , data : null } )
275+ sendSSEError ( '提问次数用完啦 | Question limit reached' )
276+ sendSSEEnd ( )
277+ res . end ( )
255278 return
256279 }
257280 }
258281 }
259282
260283 if ( config . auditConfig . enabled || config . auditConfig . customizeEnabled ) {
261284 if ( ! user . roles . includes ( UserRole . Admin ) && await containsSensitiveWords ( config . auditConfig , prompt ) ) {
262- res . send ( { status : 'Fail' , message : '含有敏感词 | Contains sensitive words' , data : null } )
285+ sendSSEError ( '含有敏感词 | Contains sensitive words' )
286+ sendSSEEnd ( )
287+ res . end ( )
263288 return
264289 }
265290 }
291+
266292 message = regenerate ? await getChat ( roomId , uuid ) : await insertChat ( uuid , prompt , uploadFileKeys , roomId , model , options as ChatOptions )
267- let firstChunk = true
293+
268294 result = await chatReplyProcess ( {
269295 message : prompt ,
270296 uploadFileKeys,
271297 parentMessageId : options ?. parentMessageId ,
272298 process : ( chunk : ResponseChunk ) => {
273299 lastResponse = chunk
274300
275- res . write ( firstChunk ? JSON . stringify ( chunk ) : `\n${ JSON . stringify ( chunk ) } ` )
276- firstChunk = false
301+ // set sse event by different data type
302+ if ( chunk . searchQuery ) {
303+ sendSSEData ( 'search_query' , { searchQuery : chunk . searchQuery } )
304+ }
305+ if ( chunk . searchResults ) {
306+ sendSSEData ( 'search_results' , {
307+ searchResults : chunk . searchResults ,
308+ searchUsageTime : chunk . searchUsageTime ,
309+ } )
310+ }
311+ if ( chunk . delta ) {
312+ // send SSE event with delta type
313+ sendSSEData ( 'delta' , { m : chunk . delta } )
314+ }
315+ else {
316+ // send all data
317+ sendSSEData ( 'message' , {
318+ id : chunk . id ,
319+ reasoning : chunk . reasoning ,
320+ text : chunk . text ,
321+ role : chunk . role ,
322+ finish_reason : chunk . finish_reason ,
323+ } )
324+ }
277325 } ,
278326 systemMessage,
279327 temperature,
@@ -283,11 +331,17 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
283331 room,
284332 chatUuid : uuid ,
285333 } )
286- // return the whole response including usage
287- res . write ( `\n${ JSON . stringify ( result . data ) } ` )
334+
335+ // 发送最终完成数据
336+ if ( result && result . status === 'Success' ) {
337+ sendSSEData ( 'complete' , result . data )
338+ }
339+
340+ sendSSEEnd ( )
288341 }
289342 catch ( error ) {
290- res . write ( JSON . stringify ( { message : error ?. message } ) )
343+ sendSSEError ( error ?. message || 'Unknown error' )
344+ sendSSEEnd ( )
291345 }
292346 finally {
293347 res . end ( )
@@ -299,7 +353,7 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
299353 }
300354
301355 if ( result . data === undefined )
302- // eslint-disable-next-line no-unsafe-finally
356+ // eslint-disable-next-line no-unsafe-finally
303357 return
304358
305359 if ( regenerate && message . options . messageId ) {
0 commit comments