diff --git a/web/chat.js b/web/chat.js
index de4db89..992ff6c 100644
--- a/web/chat.js
+++ b/web/chat.js
@@ -1,39 +1,111 @@
// All comments are in English.
let conversationId = null;
+let conversations = [];
-function login() {
- window.location = "/login";
+async function login() {
+ window.location = "/login";
+}
+
+function toggleTheme() {
+ document.body.classList.toggle("dark");
+}
+
+async function loadConversations() {
+ const r = await fetch("/api/conversations");
+ conversations = await r.json();
+ renderTabs();
+}
+
+function renderTabs() {
+ const tabs = document.getElementById("tabs");
+ tabs.innerHTML = "";
+ conversations.forEach(c => {
+ const btn = document.createElement("button");
+ btn.textContent = c.title;
+ btn.onclick = () => selectConversation(c.id);
+ tabs.appendChild(btn);
+ });
}
async function newConversation() {
- const r = await fetch("/api/new_conversation");
- const data = await r.json();
- conversationId = data.conversation_id;
- document.getElementById("chat").innerHTML = "";
+ const title = prompt("Conversation title:");
+ const r = await fetch("/api/new_conversation", {
+ method: "POST",
+ headers: {"Content-Type": "application/json"},
+ body: JSON.stringify({title})
+ });
+ const data = await r.json();
+ conversationId = data.conversation_id;
+ await loadConversations();
+ await loadHistory();
+}
+
+async function selectConversation(id) {
+ conversationId = id;
+ await loadHistory();
+}
+
+async function loadHistory() {
+ const r = await fetch(`/api/history/${conversationId}`);
+ const msgs = await r.json();
+ const chat = document.getElementById("chat");
+ chat.innerHTML = "";
+ msgs.forEach(m => {
+ const div = document.createElement("div");
+ div.className = "msg " + m.role;
+ div.innerHTML = `
${m.role === "user" ? "🧑" : "🤖"}
+ ${m.content}
`;
+ chat.appendChild(div);
+ });
}
async function sendMessage() {
- const prompt = document.getElementById("prompt").value;
- const model = "llama3.2";
+ const promptText = document.getElementById("prompt").value;
+ const file = document.getElementById("attachment").files[0];
- const chatBox = document.getElementById("chat");
- chatBox.innerHTML += `${prompt}
`;
+ if (!conversationId) {
+ await newConversation();
+ }
- const url = `/api/stream?conversation_id=${conversationId}&model=${model}&prompt=${encodeURIComponent(prompt)}`;
- const evtSource = new EventSource(url);
+ if (file) {
+ const form = new FormData();
+ form.append("file", file);
+ await fetch(`/api/attachment/${conversationId}`, {
+ method: "POST",
+ body: form
+ });
+ }
- let buffer = "";
+ const chat = document.getElementById("chat");
+ const userDiv = document.createElement("div");
+ userDiv.className = "msg user";
+ userDiv.innerHTML = `🧑
+ ${marked.parse(promptText)}
`;
+ chat.appendChild(userDiv);
- evtSource.onmessage = function(event) {
- const data = JSON.parse(event.data);
- buffer += data.token;
+ const assistantDiv = document.createElement("div");
+ assistantDiv.className = "msg assistant streaming";
+ assistantDiv.innerHTML = `🤖
+ ▌
`;
+ chat.appendChild(assistantDiv);
- document.getElementById("chat").innerHTML +=
- `${buffer}
`;
- };
+ const url = `/api/stream?conversation_id=${conversationId}&model=llama3.2&prompt=${encodeURIComponent(promptText)}`;
+ const evtSource = new EventSource(url);
- evtSource.onerror = function() {
- evtSource.close();
- };
+ let buffer = "";
+ const streamSpan = document.getElementById("stream-text");
+
+ evtSource.onmessage = (event) => {
+ const data = JSON.parse(event.data);
+ buffer += data.token;
+ streamSpan.innerHTML = marked.parse(buffer);
+ };
+
+ evtSource.onerror = () => {
+ evtSource.close();
+ assistantDiv.classList.remove("streaming");
+ };
}
+
+window.onload = loadConversations;