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;