File size: 1,960 Bytes
86f402d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
interface StreamChatCallbacks {
  onText: (chunk: string) => void;
  onToolStart: (tool: string, callId: string) => void;
  onToolResult: (tool: string, callId: string, result: Record<string, unknown>) => void;
  onDone: () => void;
  onError: (message: string) => void;
}

export async function streamChatMessage(
  patientId: string,
  content: string,
  image: File | null,
  callbacks: StreamChatCallbacks
): Promise<void> {
  try {
    const formData = new FormData();
    formData.append('content', content);
    if (image) formData.append('image', image);

    const response = await fetch(`/api/patients/${patientId}/chat`, {
      method: 'POST',
      body: formData,
    });

    const reader = response.body?.getReader();
    const decoder = new TextDecoder();

    if (!reader) {
      callbacks.onDone();
      return;
    }

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

      const text = decoder.decode(value);
      const lines = text.split('\n').filter(l => l.startsWith('data: '));

      for (const line of lines) {
        const data = line.slice('data: '.length);
        try {
          const event = JSON.parse(data);
          if (event.type === 'text') {
            callbacks.onText(event.content ?? '');
          } else if (event.type === 'tool_start') {
            callbacks.onToolStart(event.tool, event.call_id);
          } else if (event.type === 'tool_result') {
            callbacks.onToolResult(event.tool, event.call_id, event.result ?? {});
          } else if (event.type === 'done') {
            callbacks.onDone();
            return;
          } else if (event.type === 'error') {
            callbacks.onError(event.message ?? 'Unknown error');
          }
        } catch {
          // skip malformed lines
        }
      }
    }
    callbacks.onDone();
  } catch (error) {
    console.error('Stream error:', error);
    callbacks.onError(String(error));
  }
}