File size: 2,994 Bytes
194aaa5
 
 
8b922e3
5d04207
194aaa5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5083221
 
194aaa5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6a9176f
 
 
 
 
 
 
 
 
 
 
5083221
 
6a9176f
194aaa5
6a9176f
194aaa5
6a9176f
 
 
 
194aaa5
6a9176f
 
 
194aaa5
6a9176f
194aaa5
6a9176f
 
194aaa5
6a9176f
 
 
 
 
 
 
 
194aaa5
 
6a9176f
 
5451b32
 
194aaa5
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import type { DocumentInfo, Message, Source } from '../types';
import { getAuthHeaders } from '../lib/auth';

export const API_URL = import.meta.env.VITE_API_URL ?? '/api';


export async function fetchDocuments(): Promise<DocumentInfo[]> {
  const res = await fetch(`${API_URL}/documents`, {
    headers: {
      'Content-Type': 'application/json',
      ...getAuthHeaders(),
    },
  });
  if (!res.ok) throw new Error('Failed to fetch documents');
  return res.json();
}

export async function uploadDocument(file: File): Promise<void> {
  const formData = new FormData();
  formData.append('file', file);

  const res = await fetch(`${API_URL}/documents/upload`, {
    method: 'POST',
    headers: {
      ...getAuthHeaders(),
    },
    body: formData,
  });

  if (!res.ok) {
    const errData = await res.json().catch(() => ({}));
    throw new Error(errData.detail || `Upload failed (${res.status})`);
  }
}

export async function deleteDocument(id: string): Promise<void> {
  const res = await fetch(`${API_URL}/documents/${id}`, {
    method: 'DELETE',
    headers: {
      ...getAuthHeaders(),
    },
  });

  if (!res.ok) throw new Error('Failed to delete document');
}

export interface StreamChatPayload {
  messages: Message[];
  document_id: string | null;
}

export interface StreamChatCallbacks {
  onChunk: (displayContent: string, sources: Source[] | undefined) => void;
  onError: (message: string) => void;
}

export async function streamChat(

  payload: StreamChatPayload,

  callbacks: StreamChatCallbacks

): Promise<void> {
  try {
    const res = await fetch(`${API_URL}/chat`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...getAuthHeaders(),
      },
      body: JSON.stringify(payload),
    });

    if (!res.ok) {
      const errData = await res.json().catch(() => ({}));
      throw new Error(errData.detail || `Chat request failed (${res.status})`);
    }

    if (!res.body) throw new Error('No response body for streaming');

    const reader = res.body.getReader();
    const decoder = new TextDecoder();
    let streamedContent = '';
    const delimiter = '\n__SOURCES__:';

    while (true) {
      const { value, done } = await reader.read();
      if (done) break;

      streamedContent += decoder.decode(value, { stream: true });

      let displayContent = streamedContent;
      let sources: Source[] | undefined = undefined;

      if (streamedContent.includes(delimiter)) {
        const parts = streamedContent.split(delimiter);
        displayContent = parts[0];
        try {
          sources = JSON.parse(parts[1]);
        } catch {
          // Stream might be incomplete; wait for next chunk
        }
      }

      callbacks.onChunk(displayContent, sources);
    }
  } catch (error: unknown) {
    callbacks.onError(error instanceof Error ? error.message : 'Chat request failed');
  }
}