File size: 3,694 Bytes
fccc18d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
108
109
110
111
112
113
// events_helper.js
import { updateLastMessage, autoResizeTextarea } from './utils.js';
import { renderCurrentSession, sessions, currentSessionIndex } from './sessions.js';
import { callLLMStream, callLLMSummaryBatch } from './api.js';

export let attachedFiles = [];

/**
 * Convert a file to its Base64 string.
 */
export async function fileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      const base64 = reader.result.split(',')[1];
      resolve({
        name: file.name,
        path: file.webkitRelativePath || file.path || file.name,
        size: file.size,
        type: file.type,
        content: base64,
      });
    };
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

/**
 * Update the file attachments UI.
 */
export function updateFileAttachments() {
  const fileAttachments = document.getElementById('fileAttachments');
  fileAttachments.innerHTML = "";
  attachedFiles.forEach((file, index) => {
    const fileDiv = document.createElement("div");
    fileDiv.className = "file-item";
    fileDiv.innerHTML = `<span>${file.name}</span> <button data-index="${index}">&times;</button>`;
    fileAttachments.appendChild(fileDiv);
  });
  document.querySelectorAll(".file-item button").forEach(btn => {
    btn.addEventListener("click", (e) => {
      const idx = e.target.getAttribute("data-index");
      attachedFiles.splice(idx, 1);
      updateFileAttachments();
    });
  });
}

/**
 * Add a new conversation message and stream the AI response.
 */
export async function addConversation(userText) {
  if (userText.trim() === '' && attachedFiles.length === 0) return;
  const session = sessions[currentSessionIndex];
  session.messages.push({
    userText,
    aiResponse: "",
    attachments: await Promise.all(attachedFiles.map(fileToBase64)),
    model: session.settings.model,
    timestamp: new Date().toISOString(),
    maxTokens: session.settings.maxTokens,
    temperature: session.settings.temperature,
    persona: session.settings.persona,
    sessionId: session.id,
  });
  
  // Clear attachments
  attachedFiles.length = 0;
  updateFileAttachments();
  renderCurrentSession();
  
  // Build conversation context for API
  const conversation = [];
  session.messages.forEach(msg => {
    conversation.push({ role: "user", content: msg.userText, attachments: msg.attachments, sessionId: msg.sessionId });
    if (msg.aiResponse) {
      conversation.push({ role: "assistant", content: msg.aiResponse, sessionId: msg.sessionId });
    }
  });
  
  window.currentStreamController = new AbortController();
  window.isStreaming = true;
  const sendBtn = document.getElementById('sendBtn');
  sendBtn.innerHTML = `<img src="assets/stop.svg" alt="Stop Icon" class="svg-icon-non-white">`;
  
  try {
    const aiResponse = await callLLMStream(conversation, window.currentStreamController.signal);
    session.messages[session.messages.length - 1].aiResponse = aiResponse;
    renderCurrentSession();
    if (session.settings.enableSummarization) {
      await callLLMSummaryBatch(
        session.id,
        session.messages,
        session.settings.model,
        session.settings.temperature,
        session.settings.maxTokens
      );
    }
  } catch (err) {
    if (err.name === 'AbortError') {
      console.log('Streaming aborted by user.');
    } else {
      console.error(err);
      session.messages[session.messages.length - 1].aiResponse = "Error: " + err.message;
      renderCurrentSession();
    }
  } finally {
    sendBtn.innerHTML = `<img src="assets/send.svg" alt="Send Icon" class="svg-icon-non-white">`;
    window.isStreaming = false;
  }
}