choizhang commited on
Commit
3def05c
·
1 Parent(s): 1cf8d77

refactor(lightrag): use fetch replace axios

Browse files
Files changed (1) hide show
  1. lightrag_webui/src/api/lightrag.ts +81 -45
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
- let buffer = ''
282
- await axiosInstance
283
- .post('/query/stream', request, {
284
- responseType: 'text',
285
- headers: {
286
- Accept: 'application/x-ndjson'
287
- },
288
- transformResponse: [
289
- (data: string) => {
290
- // Accumulate the data and process complete lines
291
- buffer += data
292
- const lines = buffer.split('\n')
293
- // Keep the last potentially incomplete line in the buffer
294
- buffer = lines.pop() || ''
295
-
296
- for (const line of lines) {
297
- if (line.trim()) {
298
- try {
299
- const parsed = JSON.parse(line)
300
- if (parsed.response) {
301
- onChunk(parsed.response)
302
- } else if (parsed.error && onError) {
303
- onError(parsed.error)
304
- }
305
- } catch (e) {
306
- console.error('Error parsing stream chunk:', e)
307
- if (onError) onError('Error parsing server response')
308
- }
309
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  }
311
- return data
 
 
312
  }
313
- ]
314
- })
315
- .catch((error) => {
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('Error parsing server response')
331
  }
332
  }
 
333
  } catch (error) {
334
- const message = errorMessage(error)
335
- console.error('Stream request failed:', message)
336
- if (onError) onError(message)
 
 
 
 
 
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 })