dandi commited on
Commit
a67c779
·
1 Parent(s): 0d4ab93

fix: detect stream completion without [DONE] marker

Browse files
Files changed (1) hide show
  1. api/v1/chat/completions.js +19 -4
api/v1/chat/completions.js CHANGED
@@ -48,6 +48,21 @@ function extractOutputText(sseEvents) {
48
  return text;
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  function buildContinueBody(originalBody, partialOutput) {
52
  const messages = [...(originalBody.messages || [])];
53
  if (partialOutput) {
@@ -114,7 +129,7 @@ function streamWithAutoContinue(clientRes, initialResult, body, keys, getNextKey
114
  }
115
  }
116
 
117
- if (allLines.some(l => l === "data: [DONE]")) {
118
  finish();
119
  return;
120
  }
@@ -130,7 +145,7 @@ function streamWithAutoContinue(clientRes, initialResult, body, keys, getNextKey
130
  stream.on("error", () => {
131
  clearInterval(keepalive);
132
  const partialOutput = extractOutputText(allLines);
133
- if (allLines.some(l => l === "data: [DONE]")) {
134
  finish();
135
  return;
136
  }
@@ -142,7 +157,7 @@ function streamWithAutoContinue(clientRes, initialResult, body, keys, getNextKey
142
  stream.on("close", () => {
143
  if (!done) {
144
  clearInterval(keepalive);
145
- if (allLines.some(l => l === "data: [DONE]")) {
146
  finish();
147
  return;
148
  }
@@ -233,7 +248,7 @@ async function autoContinue(body, keys, getNextKey, clientRes, partialOutput, st
233
  result.stream.on("close", finish);
234
  });
235
 
236
- if (!allLines.some(l => l === "data: [DONE]")) {
237
  const newPartial = extractOutputText(allLines);
238
  await autoContinue(body, keys, getNextKey, clientRes, partialOutput + newPartial, startTime, attempt + 1);
239
  }
 
48
  return text;
49
  }
50
 
51
+ function isStreamComplete(allLines) {
52
+ for (let i = allLines.length - 1; i >= 0; i--) {
53
+ const line = allLines[i];
54
+ if (line === "data: [DONE]") return true;
55
+ if (line.startsWith("data: ")) {
56
+ try {
57
+ const parsed = JSON.parse(line.slice(6));
58
+ if (parsed.choices && parsed.choices[0] && parsed.choices[0].finish_reason) return true;
59
+ } catch {}
60
+ return false;
61
+ }
62
+ }
63
+ return false;
64
+ }
65
+
66
  function buildContinueBody(originalBody, partialOutput) {
67
  const messages = [...(originalBody.messages || [])];
68
  if (partialOutput) {
 
129
  }
130
  }
131
 
132
+ if (isStreamComplete(allLines)) {
133
  finish();
134
  return;
135
  }
 
145
  stream.on("error", () => {
146
  clearInterval(keepalive);
147
  const partialOutput = extractOutputText(allLines);
148
+ if (isStreamComplete(allLines)) {
149
  finish();
150
  return;
151
  }
 
157
  stream.on("close", () => {
158
  if (!done) {
159
  clearInterval(keepalive);
160
+ if (isStreamComplete(allLines)) {
161
  finish();
162
  return;
163
  }
 
248
  result.stream.on("close", finish);
249
  });
250
 
251
+ if (!isStreamComplete(allLines)) {
252
  const newPartial = extractOutputText(allLines);
253
  await autoContinue(body, keys, getNextKey, clientRes, partialOutput + newPartial, startTime, attempt + 1);
254
  }