@@ -204,7 +204,7 @@ export default {
204204 }
205205 } ,
206206
207- // ---------------------- 流式响应处理(重构并去重 ) ----------------------
207+ // ---------------------- 流式响应处理(改进 ) ----------------------
208208 async handleStreamResponse ( fetchResponse , requestId , modelName ) {
209209 const { readable, writable } = new TransformStream ( ) ;
210210 const writer = writable . getWriter ( ) ;
@@ -215,8 +215,9 @@ export default {
215215 await writer . write ( encoder . encode ( `data: ${ payload } \n\n` ) ) ;
216216 } ;
217217
218- // 用于去重:记录上一次完整接收到的 delta 内容
218+ // 用于去重和累积内容
219219 let previousDelta = "" ;
220+ let cumulativeContent = "" ; // 累积完整内容,解决断流问题
220221
221222 const processStream = async ( ) => {
222223 try {
@@ -227,67 +228,29 @@ export default {
227228
228229 while ( true ) {
229230 const { done, value } = await reader . read ( ) ;
230- if ( done ) break ;
231+ if ( done ) {
232+ // 确保最后一个缓冲区也被处理
233+ if ( buffer . trim ( ) ) {
234+ await processBuffer ( buffer ) ;
235+ }
236+ break ;
237+ }
231238
232239 const chunkStr = decoder . decode ( value , { stream : true } ) ;
233240 buffer += chunkStr ;
234241
235- // SSE 消息通常以 "\n\n" 分隔
236- const parts = buffer . split ( '\n\n' ) ;
237- buffer = parts . pop ( ) || '' ;
238-
239- for ( const part of parts ) {
240- if ( ! part . trim ( ) ) continue ;
241-
242- const lines = part . split ( '\n' ) ;
243- for ( const line of lines ) {
244- if ( ! line . startsWith ( 'data: ' ) ) continue ;
245-
246- const dataStr = line . slice ( 'data: ' . length ) . trim ( ) ;
247- if ( dataStr === '[DONE]' ) {
248- await sendSSE ( '[DONE]' ) ;
249- console . log ( '收到 [DONE],流结束' ) ;
250- break ;
251- }
252-
253- try {
254- const jsonData = JSON . parse ( dataStr ) ;
255- const delta = jsonData ?. choices ?. [ 0 ] ?. delta ;
256- if ( ! delta ) continue ;
257-
258- let currentDelta = delta . content || "" ;
259- // 去除重复:如果当前内容以上次完整内容为前缀,则只保留新增部分
260- let newContent = currentDelta ;
261- if ( previousDelta && currentDelta . startsWith ( previousDelta ) ) {
262- newContent = currentDelta . substring ( previousDelta . length ) ;
263- }
264- previousDelta = currentDelta ;
265- if ( ! newContent ) continue ;
266-
267- const openaiChunk = {
268- id : `chatcmpl-${ requestId } ` ,
269- object : 'chat.completion.chunk' ,
270- created : Date . now ( ) ,
271- model : modelName ,
272- choices : [
273- {
274- index : 0 ,
275- delta : isFirstChunk
276- ? { role : 'assistant' , content : newContent }
277- : { content : newContent } ,
278- finish_reason : null
279- }
280- ]
281- } ;
282-
283- if ( isFirstChunk ) isFirstChunk = false ;
284- await sendSSE ( JSON . stringify ( openaiChunk ) ) ;
285- } catch ( err ) {
286- console . error ( '解析 SSE JSON 失败:' , dataStr , err ) ;
287- }
288- }
242+ // 更可靠的处理方式:按照 SSE 规范处理双换行符分隔的消息
243+ await processBuffer ( buffer ) ;
244+
245+ // 仅保留可能不完整的最后一部分
246+ const lastBoundaryIndex = buffer . lastIndexOf ( '\n\n' ) ;
247+ if ( lastBoundaryIndex !== - 1 ) {
248+ buffer = buffer . substring ( lastBoundaryIndex + 2 ) ;
289249 }
290250 }
251+
252+ // 确保发送最终 DONE 信号
253+ console . log ( `流处理完成,累积内容长度: ${ cumulativeContent . length } ` ) ;
291254 await sendSSE ( '[DONE]' ) ;
292255 } catch ( err ) {
293256 console . error ( '处理 SSE 流时出错:' , err ) ;
@@ -305,14 +268,100 @@ export default {
305268 ]
306269 } ;
307270 try {
308- await writer . write ( encoder . encode ( `data: ${ JSON . stringify ( errorChunk ) } \n\n` ) ) ;
309- await writer . write ( encoder . encode ( 'data: [DONE]\n\n' ) ) ;
271+ await sendSSE ( JSON . stringify ( errorChunk ) ) ;
272+ await sendSSE ( ' [DONE]' ) ;
310273 } catch ( _ ) { }
311274 } finally {
312275 await writer . close ( ) ;
313276 }
314277 } ;
315278
279+ // 处理缓冲区内的完整 SSE 消息
280+ const processBuffer = async ( buffer ) => {
281+ // 按 data: 行分割
282+ const dataLineRegex = / ^ d a t a : ( .+ ) $ / gm;
283+ let match ;
284+
285+ while ( ( match = dataLineRegex . exec ( buffer ) ) !== null ) {
286+ const dataStr = match [ 1 ] . trim ( ) ;
287+
288+ if ( dataStr === '[DONE]' ) {
289+ await sendSSE ( '[DONE]' ) ;
290+ console . log ( '收到 [DONE],流结束' ) ;
291+ continue ;
292+ }
293+
294+ try {
295+ const jsonData = JSON . parse ( dataStr ) ;
296+ const delta = jsonData ?. choices ?. [ 0 ] ?. delta ;
297+ if ( ! delta ) continue ;
298+
299+ let currentDelta = delta . content || "" ;
300+
301+ // 改进的去重逻辑:如果有完整内容,检查是否为前缀
302+ if ( currentDelta ) {
303+ let newContent = currentDelta ;
304+ let needsSending = true ;
305+
306+ if ( previousDelta && currentDelta . startsWith ( previousDelta ) ) {
307+ // 只提取新增部分
308+ newContent = currentDelta . substring ( previousDelta . length ) ;
309+ // 如果没有新增内容,跳过发送
310+ if ( ! newContent ) needsSending = false ;
311+ }
312+
313+ if ( needsSending ) {
314+ // 创建并发送内容块
315+ const openaiChunk = {
316+ id : `chatcmpl-${ requestId } ` ,
317+ object : 'chat.completion.chunk' ,
318+ created : Date . now ( ) ,
319+ model : modelName ,
320+ choices : [
321+ {
322+ index : 0 ,
323+ delta : isFirstChunk
324+ ? { role : 'assistant' , content : newContent }
325+ : { content : newContent } ,
326+ finish_reason : null
327+ }
328+ ]
329+ } ;
330+
331+ if ( isFirstChunk ) isFirstChunk = false ;
332+ await sendSSE ( JSON . stringify ( openaiChunk ) ) ;
333+
334+ // 累积内容
335+ cumulativeContent += newContent ;
336+ }
337+
338+ // 更新之前的内容为当前完整内容
339+ previousDelta = currentDelta ;
340+ }
341+
342+ // 处理完成标志
343+ if ( jsonData ?. choices ?. [ 0 ] ?. finish_reason ) {
344+ const finishChunk = {
345+ id : `chatcmpl-${ requestId } ` ,
346+ object : 'chat.completion.chunk' ,
347+ created : Date . now ( ) ,
348+ model : modelName ,
349+ choices : [
350+ {
351+ index : 0 ,
352+ delta : { } ,
353+ finish_reason : jsonData . choices [ 0 ] . finish_reason
354+ }
355+ ]
356+ } ;
357+ await sendSSE ( JSON . stringify ( finishChunk ) ) ;
358+ }
359+ } catch ( err ) {
360+ console . error ( '解析 SSE JSON 失败:' , dataStr , err ) ;
361+ }
362+ }
363+ } ;
364+
316365 processStream ( ) ;
317366 return new Response ( readable , {
318367 headers : {
0 commit comments