AskMe / app.js
kvashist's picture
Create app.js
c613ef8 verified
const CHAT_URL = "/api/chat";
const MODEL = "llama3:latest";
const BASE_SYSTEM = "You are helpful.";
const chatEl = document.getElementById("chat");
const formEl = document.getElementById("form");
const promptEl = document.getElementById("prompt");
const searchBtn = document.getElementById("searchBtn");
const sendBtn = document.getElementById("sendBtn");
const statusDot = document.getElementById("statusDot");
const statusText = document.getElementById("statusText");
const heroEl = document.getElementById("hero");
let searchMode = false;
function addMessage(role, text, { highlight = false } = {}) {
const msg = document.createElement("div");
msg.className = `msg ${role}${highlight ? " highlight" : ""}`;
const bubble = document.createElement("div");
bubble.className = "bubble";
bubble.textContent = text;
msg.appendChild(bubble);
chatEl.appendChild(msg);
chatEl.scrollTop = chatEl.scrollHeight;
if (heroEl) heroEl.style.display = "none";
return msg;
}
function setConnected(ok) {
statusDot.classList.toggle("on", ok);
statusText.textContent = ok ? "Connected" : "Disconnected";
}
async function pingProxy() {
try {
const r = await fetch("/health");
setConnected(r.ok);
} catch {
setConnected(false);
}
}
function autosizeTextarea(el) {
el.style.height = "auto";
el.style.height = Math.min(el.scrollHeight, 180) + "px";
}
promptEl.addEventListener("input", () => autosizeTextarea(promptEl));
promptEl.addEventListener("keydown", (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
formEl.requestSubmit();
}
});
searchBtn.addEventListener("click", () => {
searchMode = !searchMode;
searchBtn.setAttribute("aria-pressed", String(searchMode));
});
formEl.addEventListener("submit", async (e) => {
e.preventDefault();
const userText = promptEl.value.trim();
if (!userText) return;
addMessage("user", userText);
promptEl.value = "";
autosizeTextarea(promptEl);
sendBtn.disabled = true;
const placeholder = addMessage("ai", "Thinking…");
try {
const body = {
model: MODEL,
messages: [
{ role: "system", content: BASE_SYSTEM },
{ role: "user", content: userText }
],
stream: false
};
const resp = await fetch(CHAT_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body)
});
if (!resp.ok) {
const err = await resp.text();
placeholder.querySelector(".bubble").textContent = `Error (${resp.status}): ${err}`;
placeholder.classList.add("highlight");
return;
}
const data = await resp.json();
const answer = data?.message?.content ?? "(No content)";
placeholder.querySelector(".bubble").textContent = answer;
placeholder.classList.add("highlight");
setTimeout(() => placeholder.classList.remove("highlight"), 1200);
} catch (err) {
placeholder.querySelector(".bubble").textContent = `Request failed: ${err?.message ?? String(err)}`;
placeholder.classList.add("highlight");
} finally {
sendBtn.disabled = false;
promptEl.focus();
await pingProxy();
}
});
pingProxy();
setInterval(pingProxy, 5000);