Spaces:
Sleeping
Sleeping
wuyiqunLu
commited on
fix: when api sending multiple chunks together with incomplete json (#52)
Browse files- app/api/vision-agent/route.ts +67 -60
app/api/vision-agent/route.ts
CHANGED
@@ -10,6 +10,46 @@ import { cleanAnswerMessage, cleanInputMessage } from '@/lib/messageUtils';
|
|
10 |
export const dynamic = 'force-dynamic';
|
11 |
export const maxDuration = 300; // This function can run for a maximum of 5 minutes
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
export const POST = withLogging(
|
14 |
async (
|
15 |
session,
|
@@ -110,74 +150,41 @@ export const POST = withLogging(
|
|
110 |
|
111 |
if (fetchResponse.body) {
|
112 |
const encoder = new TextEncoder();
|
113 |
-
const decoder = new TextDecoder();
|
|
|
114 |
const stream = fetchResponse.body.pipeThrough(
|
115 |
new TransformStream({
|
116 |
transform: async (chunk, controller) => {
|
117 |
-
const data = decoder.decode(chunk);
|
118 |
-
|
|
|
|
|
|
|
119 |
if (!line.trim()) {
|
120 |
-
|
121 |
}
|
122 |
-
|
123 |
-
const
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
message +=
|
135 |
-
new Array(keys.length + 1).fill('|').join(' :- ') + '\n';
|
136 |
-
arr.forEach((obj: any) => {
|
137 |
-
message +=
|
138 |
-
'| ' +
|
139 |
-
keys.map(key => obj[key]).join(' | ') +
|
140 |
-
' |' +
|
141 |
-
'\n';
|
142 |
-
});
|
143 |
-
message += '\n';
|
144 |
}
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
});
|
152 |
-
message += '\n';
|
153 |
-
}
|
154 |
-
if (json.code) {
|
155 |
-
message += `\`\`\`python\n${json.code}\n\`\`\`\n`;
|
156 |
-
}
|
157 |
-
if (json.result) {
|
158 |
-
message += `\`\`\`\n${json.result}\n\`\`\`\n`;
|
159 |
-
}
|
160 |
-
|
161 |
-
logger.info(
|
162 |
-
session,
|
163 |
-
{
|
164 |
-
message,
|
165 |
-
},
|
166 |
-
request,
|
167 |
-
'__AGENT_RESPONSE',
|
168 |
-
);
|
169 |
controller.enqueue(encoder.encode(message));
|
170 |
-
} catch (e) {
|
171 |
-
console.log(data);
|
172 |
-
logger.error(
|
173 |
-
session,
|
174 |
-
{ message: (e as Error).message, data },
|
175 |
-
request,
|
176 |
-
);
|
177 |
-
controller.error(e);
|
178 |
-
controller.terminate();
|
179 |
}
|
180 |
-
}
|
181 |
},
|
182 |
}),
|
183 |
);
|
|
|
10 |
export const dynamic = 'force-dynamic';
|
11 |
export const maxDuration = 300; // This function can run for a maximum of 5 minutes
|
12 |
|
13 |
+
const parseLine = (line: string) => {
|
14 |
+
try {
|
15 |
+
const json = JSON.parse(line);
|
16 |
+
let message = (json.log ?? '') + '\n';
|
17 |
+
if (json.task || json.plan || json.reflection) {
|
18 |
+
const arr = json.plan
|
19 |
+
? json.plan
|
20 |
+
: json.task
|
21 |
+
? [json.task]
|
22 |
+
: [json.reflection];
|
23 |
+
const keys = Object.keys(arr[0]);
|
24 |
+
message += '\n';
|
25 |
+
message += '| ' + keys.join(' | ') + ' |' + '\n';
|
26 |
+
message += new Array(keys.length + 1).fill('|').join(' :- ') + '\n';
|
27 |
+
arr.forEach((obj: any) => {
|
28 |
+
message += '| ' + keys.map(key => obj[key]).join(' | ') + ' |' + '\n';
|
29 |
+
});
|
30 |
+
message += '\n';
|
31 |
+
}
|
32 |
+
if (json.tools) {
|
33 |
+
message += '\n';
|
34 |
+
message += '| ' + 'Descriptions' + ' |' + '\n';
|
35 |
+
message += '| ' + ':-' + ' |' + '\n';
|
36 |
+
json.tools.forEach((tool: string) => {
|
37 |
+
message += '| ' + tool + ' |' + '\n';
|
38 |
+
});
|
39 |
+
message += '\n';
|
40 |
+
}
|
41 |
+
if (json.code) {
|
42 |
+
message += `\`\`\`python\n${json.code}\n\`\`\`\n`;
|
43 |
+
}
|
44 |
+
if (json.result) {
|
45 |
+
message += `\`\`\`\n${json.result}\n\`\`\`\n`;
|
46 |
+
}
|
47 |
+
return { message };
|
48 |
+
} catch (e) {
|
49 |
+
return { error: e };
|
50 |
+
}
|
51 |
+
};
|
52 |
+
|
53 |
export const POST = withLogging(
|
54 |
async (
|
55 |
session,
|
|
|
150 |
|
151 |
if (fetchResponse.body) {
|
152 |
const encoder = new TextEncoder();
|
153 |
+
const decoder = new TextDecoder('utf-8');
|
154 |
+
let buffer = '';
|
155 |
const stream = fetchResponse.body.pipeThrough(
|
156 |
new TransformStream({
|
157 |
transform: async (chunk, controller) => {
|
158 |
+
const data = decoder.decode(chunk, { stream: true });
|
159 |
+
buffer += data;
|
160 |
+
let lines = buffer.split('\n');
|
161 |
+
buffer = lines.pop() ?? ''; // Save the last incomplete line back to the buffer
|
162 |
+
for (let line of lines) {
|
163 |
if (!line.trim()) {
|
164 |
+
continue;
|
165 |
}
|
166 |
+
if (line.trim()) {
|
167 |
+
const { message, error } = parseLine(line.trim());
|
168 |
+
if (message) {
|
169 |
+
controller.enqueue(encoder.encode(message));
|
170 |
+
} else if (error) {
|
171 |
+
logger.error(
|
172 |
+
session,
|
173 |
+
{ message: (error as Error).message, data },
|
174 |
+
request,
|
175 |
+
);
|
176 |
+
controller.error(error);
|
177 |
+
controller.terminate();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
178 |
}
|
179 |
+
}
|
180 |
+
}
|
181 |
+
if (buffer.trim()) {
|
182 |
+
const { message } = parseLine(buffer.trim());
|
183 |
+
if (message) {
|
184 |
+
buffer = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
controller.enqueue(encoder.encode(message));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
}
|
187 |
+
}
|
188 |
},
|
189 |
}),
|
190 |
);
|