Spaces:
Sleeping
Sleeping
| // static/js/design.js | |
| // ββ Marked.js config ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| marked.setOptions({ | |
| breaks: true, | |
| gfm: true, | |
| highlight: (code, lang) => { | |
| if (lang && hljs.getLanguage(lang)) { | |
| return hljs.highlight(code, { language: lang }).value; | |
| } | |
| return hljs.highlightAuto(code).value; | |
| } | |
| }); | |
| // ββ DOM refs ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| const chatWindow = document.getElementById("chatWindow"); | |
| const queryInput = document.getElementById("queryInput"); | |
| const sendBtn = document.getElementById("sendBtn"); | |
| const topicInput = document.getElementById("topicInput"); | |
| const clearBtn = document.getElementById("clearBtn"); | |
| const menuBtn = document.getElementById("menuBtn"); | |
| const sidebar = document.getElementById("sidebar"); | |
| const overlay = document.getElementById("overlay"); | |
| const sidebarClose = document.getElementById("sidebarClose"); | |
| const quickBtns = document.querySelectorAll(".quick-btn"); | |
| // ββ Conversation history ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| let history = []; | |
| // ββ Sidebar toggle ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function openSidebar() { | |
| sidebar.classList.add("open"); | |
| overlay.classList.add("show"); | |
| } | |
| function closeSidebar() { | |
| sidebar.classList.remove("open"); | |
| overlay.classList.remove("show"); | |
| } | |
| menuBtn.addEventListener("click", openSidebar); | |
| sidebarClose.addEventListener("click", closeSidebar); | |
| overlay.addEventListener("click", closeSidebar); | |
| // ββ Auto-resize textarea ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function autoResize() { | |
| queryInput.style.height = "auto"; | |
| queryInput.style.height = Math.min(queryInput.scrollHeight, 200) + "px"; | |
| } | |
| queryInput.addEventListener("input", autoResize); | |
| // ββ Quick prompt buttons ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| quickBtns.forEach(btn => { | |
| btn.addEventListener("click", () => { | |
| queryInput.value = btn.dataset.prompt; | |
| autoResize(); | |
| queryInput.focus(); | |
| closeSidebar(); | |
| }); | |
| }); | |
| // ββ Clear chat ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| clearBtn.addEventListener("click", () => { | |
| history = []; | |
| const welcome = document.getElementById("welcomeMsg"); | |
| chatWindow.innerHTML = ""; | |
| if (welcome) chatWindow.appendChild(welcome); | |
| }); | |
| // ββ Scroll to bottom ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function scrollToBottom() { | |
| chatWindow.scrollTo({ top: chatWindow.scrollHeight, behavior: "smooth" }); | |
| } | |
| // ββ Add message bubble ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function addMessage(role, content) { | |
| const msg = document.createElement("div"); | |
| msg.className = `message ${role}`; | |
| const avatar = document.createElement("div"); | |
| avatar.className = "avatar"; | |
| avatar.textContent = role === "user" ? "YOU" : "SS"; | |
| const bubble = document.createElement("div"); | |
| bubble.className = "bubble"; | |
| if (role === "assistant") { | |
| bubble.innerHTML = marked.parse(content); | |
| bubble.querySelectorAll("pre code").forEach(el => hljs.highlightElement(el)); | |
| } else { | |
| // user bubble: preserve newlines and show code syntax as plain text | |
| bubble.style.whiteSpace = "pre-wrap"; | |
| bubble.textContent = content; | |
| } | |
| msg.appendChild(avatar); | |
| msg.appendChild(bubble); | |
| chatWindow.appendChild(msg); | |
| scrollToBottom(); | |
| } | |
| // ββ Typing indicator ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function showTyping() { | |
| const msg = document.createElement("div"); | |
| msg.className = "message assistant"; | |
| msg.id = "typingIndicator"; | |
| const avatar = document.createElement("div"); | |
| avatar.className = "avatar"; | |
| avatar.textContent = "SS"; | |
| const bubble = document.createElement("div"); | |
| bubble.className = "bubble"; | |
| bubble.innerHTML = ` | |
| <div class="typing-indicator"> | |
| <span></span><span></span><span></span> | |
| </div>`; | |
| msg.appendChild(avatar); | |
| msg.appendChild(bubble); | |
| chatWindow.appendChild(msg); | |
| scrollToBottom(); | |
| } | |
| function hideTyping() { | |
| const indicator = document.getElementById("typingIndicator"); | |
| if (indicator) indicator.remove(); | |
| } | |
| // ββ Send message ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async function sendMessage() { | |
| const query = queryInput.value.trim(); | |
| if (!query) return; | |
| const topic = topicInput.value.trim() || null; | |
| addMessage("user", query); | |
| history.push({ role: "user", content: query }); | |
| // reset input | |
| queryInput.value = ""; | |
| queryInput.style.height = "auto"; | |
| sendBtn.disabled = true; | |
| showTyping(); | |
| try { | |
| const res = await fetch("/chat", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ query, topic, history }) | |
| }); | |
| const data = await res.json(); | |
| hideTyping(); | |
| if (data.error) { | |
| addMessage("assistant", `β οΈ **Error:** ${data.error}`); | |
| } else { | |
| addMessage("assistant", data.response); | |
| history.push({ role: "assistant", content: data.response }); | |
| } | |
| } catch (err) { | |
| hideTyping(); | |
| addMessage("assistant", "β οΈ **Network error.** Flask server se connect nahi ho saka."); | |
| } finally { | |
| sendBtn.disabled = false; | |
| queryInput.focus(); | |
| } | |
| } | |
| // ββ Keyboard handling βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| queryInput.addEventListener("keydown", (e) => { | |
| if (e.key === "Enter") { | |
| if (e.shiftKey) { | |
| // Shift+Enter β insert a real newline and resize | |
| // let the browser insert \n naturally, then resize | |
| setTimeout(autoResize, 0); | |
| return; // do NOT send | |
| } | |
| // plain Enter β send | |
| e.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| // ββ Send button βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| sendBtn.addEventListener("click", sendMessage); |