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}">×</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;
}
}
|