choizhang
commited on
Commit
·
3def05c
1
Parent(s):
1cf8d77
refactor(lightrag): use fetch replace axios
Browse files
lightrag_webui/src/api/lightrag.ts
CHANGED
@@ -277,65 +277,101 @@ export const queryTextStream = async (
|
|
277 |
onChunk: (chunk: string) => void,
|
278 |
onError?: (error: string) => void
|
279 |
) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
try {
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
310 |
}
|
311 |
-
|
|
|
|
|
312 |
}
|
313 |
-
|
314 |
-
}
|
315 |
-
|
316 |
-
if (onError) onError(errorMessage(error))
|
317 |
-
})
|
318 |
|
319 |
-
// Process any remaining data in the buffer
|
320 |
if (buffer.trim()) {
|
321 |
try {
|
322 |
-
const parsed = JSON.parse(buffer)
|
323 |
if (parsed.response) {
|
324 |
-
onChunk(parsed.response)
|
325 |
} else if (parsed.error && onError) {
|
326 |
-
onError(parsed.error)
|
327 |
}
|
328 |
} catch (e) {
|
329 |
-
console.error('Error parsing final chunk:', e)
|
330 |
-
if (onError) onError(
|
331 |
}
|
332 |
}
|
|
|
333 |
} catch (error) {
|
334 |
-
const message = errorMessage(error)
|
335 |
-
console.error('Stream request failed:', message)
|
336 |
-
if (onError)
|
|
|
|
|
|
|
|
|
|
|
337 |
}
|
338 |
-
}
|
339 |
|
340 |
export const insertText = async (text: string): Promise<DocActionResponse> => {
|
341 |
const response = await axiosInstance.post('/documents/text', { text })
|
|
|
277 |
onChunk: (chunk: string) => void,
|
278 |
onError?: (error: string) => void
|
279 |
) => {
|
280 |
+
const apiKey = useSettingsStore.getState().apiKey;
|
281 |
+
const token = localStorage.getItem('LIGHTRAG-API-TOKEN');
|
282 |
+
const headers: HeadersInit = {
|
283 |
+
'Content-Type': 'application/json',
|
284 |
+
'Accept': 'application/x-ndjson',
|
285 |
+
};
|
286 |
+
if (token) {
|
287 |
+
headers['Authorization'] = `Bearer ${token}`;
|
288 |
+
}
|
289 |
+
if (apiKey) {
|
290 |
+
headers['X-API-Key'] = apiKey;
|
291 |
+
}
|
292 |
+
|
293 |
try {
|
294 |
+
const response = await fetch(`${backendBaseUrl}/query/stream`, {
|
295 |
+
method: 'POST',
|
296 |
+
headers: headers,
|
297 |
+
body: JSON.stringify(request),
|
298 |
+
});
|
299 |
+
|
300 |
+
if (!response.ok) {
|
301 |
+
// Handle HTTP errors (e.g., 4xx, 5xx)
|
302 |
+
let errorBody = 'Unknown error';
|
303 |
+
try {
|
304 |
+
errorBody = await response.text(); // Try to get error details from body
|
305 |
+
} catch (e) { /* ignore */ }
|
306 |
+
throw new Error(`HTTP error ${response.status}: ${response.statusText}\n${errorBody}`);
|
307 |
+
}
|
308 |
+
|
309 |
+
if (!response.body) {
|
310 |
+
throw new Error('Response body is null');
|
311 |
+
}
|
312 |
+
|
313 |
+
const reader = response.body.getReader();
|
314 |
+
const decoder = new TextDecoder();
|
315 |
+
let buffer = '';
|
316 |
+
|
317 |
+
// eslint-disable-next-line no-constant-condition
|
318 |
+
while (true) {
|
319 |
+
const { done, value } = await reader.read();
|
320 |
+
if (done) {
|
321 |
+
break; // Stream finished
|
322 |
+
}
|
323 |
+
|
324 |
+
// Decode the chunk and add to buffer
|
325 |
+
buffer += decoder.decode(value, { stream: true }); // stream: true handles multi-byte chars split across chunks
|
326 |
+
|
327 |
+
// Process complete lines (NDJSON)
|
328 |
+
const lines = buffer.split('\n');
|
329 |
+
buffer = lines.pop() || ''; // Keep potentially incomplete line in buffer
|
330 |
+
|
331 |
+
for (const line of lines) {
|
332 |
+
if (line.trim()) {
|
333 |
+
try {
|
334 |
+
const parsed = JSON.parse(line);
|
335 |
+
if (parsed.response) {
|
336 |
+
console.log('Received chunk:', parsed.response); // Log for debugging
|
337 |
+
onChunk(parsed.response);
|
338 |
+
} else if (parsed.error && onError) {
|
339 |
+
onError(parsed.error);
|
340 |
}
|
341 |
+
} catch (e) {
|
342 |
+
console.error('Error parsing stream chunk:', line, e);
|
343 |
+
if (onError) onError(`Error parsing server response: ${line}`);
|
344 |
}
|
345 |
+
}
|
346 |
+
}
|
347 |
+
}
|
|
|
|
|
348 |
|
349 |
+
// Process any remaining data in the buffer after the stream ends
|
350 |
if (buffer.trim()) {
|
351 |
try {
|
352 |
+
const parsed = JSON.parse(buffer);
|
353 |
if (parsed.response) {
|
354 |
+
onChunk(parsed.response);
|
355 |
} else if (parsed.error && onError) {
|
356 |
+
onError(parsed.error);
|
357 |
}
|
358 |
} catch (e) {
|
359 |
+
console.error('Error parsing final chunk:', buffer, e);
|
360 |
+
if (onError) onError(`Error parsing final server response: ${buffer}`);
|
361 |
}
|
362 |
}
|
363 |
+
|
364 |
} catch (error) {
|
365 |
+
const message = errorMessage(error);
|
366 |
+
console.error('Stream request failed:', message);
|
367 |
+
if (onError) {
|
368 |
+
onError(message);
|
369 |
+
} else {
|
370 |
+
// If no specific onError handler, maybe throw or log more prominently
|
371 |
+
console.error("Unhandled stream error:", message);
|
372 |
+
}
|
373 |
}
|
374 |
+
};
|
375 |
|
376 |
export const insertText = async (text: string): Promise<DocActionResponse> => {
|
377 |
const response = await axiosInstance.post('/documents/text', { text })
|