@@ -225,7 +225,12 @@ router.post('/chat-clear', auth, async (req, res) => {
225
225
} )
226
226
227
227
router . 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' )
229
234
230
235
let { roomId, uuid, regenerate, prompt, uploadFileKeys, options = { } , systemMessage, temperature, top_p } = req . body as RequestProps
231
236
const userId = req . headers . userId . toString ( )
@@ -241,6 +246,22 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
241
246
let result
242
247
let message : ChatInfo
243
248
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
+
244
265
try {
245
266
// If use the fixed fakeuserid(some probability of duplicated with real ones), redefine user which is send to chatReplyProcess
246
267
if ( userId === '6406d8c50aedd633885fa16f' ) {
@@ -251,29 +272,56 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
251
272
if ( config . siteConfig ?. usageCountLimit ) {
252
273
const useAmount = user ? ( user . useAmount ?? 0 ) : 0
253
274
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 ( )
255
278
return
256
279
}
257
280
}
258
281
}
259
282
260
283
if ( config . auditConfig . enabled || config . auditConfig . customizeEnabled ) {
261
284
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 ( )
263
288
return
264
289
}
265
290
}
291
+
266
292
message = regenerate ? await getChat ( roomId , uuid ) : await insertChat ( uuid , prompt , uploadFileKeys , roomId , model , options as ChatOptions )
267
- let firstChunk = true
293
+
268
294
result = await chatReplyProcess ( {
269
295
message : prompt ,
270
296
uploadFileKeys,
271
297
parentMessageId : options ?. parentMessageId ,
272
298
process : ( chunk : ResponseChunk ) => {
273
299
lastResponse = chunk
274
300
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
+ }
277
325
} ,
278
326
systemMessage,
279
327
temperature,
@@ -283,11 +331,17 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
283
331
room,
284
332
chatUuid : uuid ,
285
333
} )
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 ( )
288
341
}
289
342
catch ( error ) {
290
- res . write ( JSON . stringify ( { message : error ?. message } ) )
343
+ sendSSEError ( error ?. message || 'Unknown error' )
344
+ sendSSEEnd ( )
291
345
}
292
346
finally {
293
347
res . end ( )
@@ -299,7 +353,7 @@ router.post('/chat-process', [auth, limiter], async (req, res) => {
299
353
}
300
354
301
355
if ( result . data === undefined )
302
- // eslint-disable-next-line no-unsafe-finally
356
+ // eslint-disable-next-line no-unsafe-finally
303
357
return
304
358
305
359
if ( regenerate && message . options . messageId ) {
0 commit comments