document.addEventListener("DOMContentLoaded", () => { // --- UI Selectors --- const sidebar = document.getElementById("sidebar"); const openSidebarBtn = document.getElementById("open-sidebar"); const closeSidebarBtn = document.getElementById("close-sidebar"); const chatMessages = document.getElementById("chat-messages"); const chatViewport = document.getElementById("chat-viewport"); const chatForm = document.getElementById("chat-form"); const userInput = document.getElementById("user-input"); const usageStats = document.getElementById("usage-stats"); const authTrigger = document.getElementById("auth-trigger"); const authModal = document.getElementById("auth-modal"); const loginForm = document.getElementById("login-form"); const signupForm = document.getElementById("signup-form"); const logoutBtn = document.getElementById("logout-btn"); const historyList = document.getElementById("history-list"); const tabBtns = document.querySelectorAll(".tab-btn"); const cpuVal = document.getElementById("cpu-val"); const ramVal = document.getElementById("ram-val"); const sysPills = document.getElementById("sys-pills"); const totalQEl = document.getElementById("total-q"); let isStreaming = false; // --- Sidebar & Navigation --- openSidebarBtn.onclick = () => { sidebar.classList.remove("sidebar-closed"); fetchHistory(); }; closeSidebarBtn.onclick = () => sidebar.classList.add("sidebar-closed"); // --- Auth Modal Logic --- authTrigger.onclick = () => authModal.classList.remove("hidden"); document.querySelector(".close-modal-btn").onclick = () => authModal.classList.add("hidden"); tabBtns.forEach(btn => { btn.onclick = () => { tabBtns.forEach(b => b.classList.remove("active")); btn.classList.add("active"); if(btn.dataset.tab === "login") { loginForm.classList.remove("hidden"); signupForm.classList.add("hidden"); } else { loginForm.classList.add("hidden"); signupForm.classList.remove("hidden"); } }; }); loginForm.onsubmit = (e) => handleAuth(e, "login"); signupForm.onsubmit = (e) => handleAuth(e, "signup"); async function handleAuth(e, action) { e.preventDefault(); const email = e.target.querySelector("input[type='email']").value; const password = e.target.querySelector("input[type='password']").value; try { const res = await fetch(`/auth/${action}`, { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({email, password}) }); const data = await res.json(); if(data.success) location.reload(); else alert(data.error); } catch(err) { alert("خطأ في الاتصال"); } } logoutBtn.onclick = async () => { await fetch("/logout"); location.reload(); }; // --- Chat & Streaming --- function appendMessage(text, type, meta = null) { const div = document.createElement("div"); div.className = `message ${type === 'user' ? 'user-msg' : 'bot-msg'}`; let metaHtml = meta ? ` ` : ''; div.innerHTML = `
${text}
${metaHtml} `; chatMessages.appendChild(div); chatViewport.scrollTop = chatViewport.scrollHeight; return div; } chatForm.onsubmit = async (e) => { e.preventDefault(); const q = userInput.value.trim(); const tier = document.getElementById("model-tier").value; if(!q || isStreaming) return; appendMessage(q, 'user'); userInput.value = ""; isStreaming = true; const botMsgDiv = document.createElement("div"); botMsgDiv.className = "message bot-msg"; const stepsContainer = document.createElement("div"); stepsContainer.className = "steps-container"; const currentStepEl = document.createElement("div"); currentStepEl.className = "generating-status active-step"; currentStepEl.innerHTML = ` جاري البدء (${tier})...`; botMsgDiv.appendChild(stepsContainer); botMsgDiv.appendChild(currentStepEl); chatMessages.appendChild(botMsgDiv); let completedSteps = new Set(); try { const res = await fetch("/chat", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({question: q, tier: tier}) }); if(!res.ok) { const err = await res.json(); botMsgDiv.innerHTML = `
❌ ${err.error}
`; isStreaming = false; return; } const reader = res.body.getReader(); const decoder = new TextDecoder(); while(true) { const {value, done} = await reader.read(); if(done) break; const lines = decoder.decode(value).split("\n"); for(const line of lines) { if(!line.trim()) continue; const data = JSON.parse(line); if(data.status === "Generating") { const stepText = data.step; const currentText = currentStepEl.querySelector("span").textContent; if (currentText !== stepText && currentText !== `جاري البدء (${tier})...`) { if (!completedSteps.has(currentText)) { const doneStep = document.createElement("div"); doneStep.className = "step-item completed"; doneStep.innerHTML = ` ${currentText}`; stepsContainer.appendChild(doneStep); completedSteps.add(currentText); } } currentStepEl.querySelector("span").textContent = stepText; } else if(data.status === "Complete" || data.response_text) { currentStepEl.remove(); const bubble = document.createElement("div"); bubble.className = "msg-bubble fade-in"; bubble.innerHTML = data.response_text; const footer = document.createElement("div"); footer.className = "msg-footer"; footer.innerHTML = ` ${data.duration.toFixed(2)}s ${data.token_count} `; botMsgDiv.appendChild(bubble); botMsgDiv.appendChild(footer); updateGlobalStatus(); } } } } catch(err) { botMsgDiv.innerHTML = `
❌ فشل في الاتصال
`; } finally { isStreaming = false; chatViewport.scrollTop = chatViewport.scrollHeight; } }; async function updateGlobalStatus() { try { const res = await fetch("/status"); const data = await res.json(); if(data.logged_in) { authTrigger.classList.add("hidden"); logoutBtn.classList.remove("hidden"); sysPills.classList.remove("hidden"); usageStats.innerHTML = ` ${data.user} ${data.tokens}/${data.max} `; } else { authTrigger.classList.remove("hidden"); logoutBtn.classList.add("hidden"); sysPills.classList.add("hidden"); usageStats.innerHTML = ` ضيف ${data.tokens}/${data.max} `; } cpuVal.textContent = data.cpu.toFixed(0); ramVal.textContent = data.ram.toFixed(0); totalQEl.textContent = data.total_questions; } catch(e) {} } async function fetchHistory() { try { const res = await fetch("/history"); const data = await res.json(); historyList.innerHTML = ""; data.reverse().forEach(item => { const div = document.createElement("div"); div.className = "history-item"; div.innerHTML = ` ${item.q.substring(0, 30)}...`; div.onclick = () => { chatMessages.innerHTML = ""; appendMessage(item.q, 'user'); appendMessage(item.a, 'bot', {duration: 0, token_count: item.tokens || 0}); sidebar.classList.add("sidebar-closed"); }; historyList.appendChild(div); }); } catch(e) {} } setInterval(updateGlobalStatus, 10000); updateGlobalStatus(); });