document.addEventListener("DOMContentLoaded", () => { const chatForm = document.getElementById("chat-form"); const userInput = document.getElementById("user-input"); const messagesContainer = document.getElementById("messages-container"); const tokenInput = document.getElementById("hf-token"); // Load saved HF Token from localStorage if present if (localStorage.getItem("hf_token")) { tokenInput.value = localStorage.getItem("hf_token"); } // Auto-resize textarea userInput.addEventListener("input", () => { userInput.style.height = "auto"; userInput.style.height = userInput.scrollHeight + "px"; }); // Handle shift+enter to submit userInput.addEventListener("keydown", (e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); chatForm.dispatchEvent(new Event("submit")); } }); // Save token changes tokenInput.addEventListener("change", () => { localStorage.setItem("hf_token", tokenInput.value.trim()); }); // Chat history state let chatHistory = []; // Parse streaming response async function handleStreamingResponse(response, messageEl, contentEl) { const reader = response.body.getReader(); const decoder = new TextDecoder("utf-8"); let buffer = ""; let fullText = ""; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop(); for (const line of lines) { const cleanLine = line.trim(); if (!cleanLine) continue; if (cleanLine.startsWith("data:")) { const dataStr = cleanLine.substring(5).trim(); if (dataStr === "[DONE]") break; try { const dataObj = JSON.parse(dataStr); const token = dataObj.choices[0].delta.content; if (token) { fullText += token; // Render Markdown contentEl.innerHTML = marked.parse(fullText); // Run Prism syntax highlighting Prism.highlightAllUnder(contentEl); // Auto scroll messagesContainer.scrollTop = messagesContainer.scrollHeight; } } catch (err) { // Suppress JSON parse errors on partial streams } } } } return fullText; } // Submit form handler chatForm.submit = async (e) => { // Fallback for form submit }; chatForm.addEventListener("submit", async (e) => { e.preventDefault(); const text = userInput.value.trim(); if (!text) return; // Reset input area userInput.value = ""; userInput.style.height = "auto"; // Append user message const userMsgEl = document.createElement("div"); userMsgEl.className = "message user-message"; userMsgEl.innerHTML = `
👤
${marked.parse(text)}
`; messagesContainer.appendChild(userMsgEl); messagesContainer.scrollTop = messagesContainer.scrollHeight; // Prepare assistant placeholder const assistantMsgEl = document.createElement("div"); assistantMsgEl.className = "message assistant-message"; assistantMsgEl.innerHTML = `
🧠
Thinking...
`; messagesContainer.appendChild(assistantMsgEl); messagesContainer.scrollTop = messagesContainer.scrollHeight; const contentEl = assistantMsgEl.querySelector(".message-content"); // Format system + history + new prompt const messages = [ { role: "system", content: "You are a helpful coding assistant. Provide clean, correct, and well-structured code when asked." }, ...chatHistory, { role: "user", content: text } ]; const token = tokenInput.value.trim(); const headers = { "Content-Type": "application/json" }; if (token) { headers["Authorization"] = `Bearer ${token}`; } try { const response = await fetch("https://api-inference.huggingface.co/models/Qwen/Qwen2.5-Coder-7B-Instruct/v1/chat/completions", { method: "POST", headers: headers, body: JSON.stringify({ model: "Qwen/Qwen2.5-Coder-7B-Instruct", messages: messages, max_tokens: 2048, temperature: 0.7, top_p: 0.9, stream: true }) }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); const errMsg = errorData.error?.message || response.statusText; contentEl.innerHTML = `API Error: ${errMsg}`; return; } contentEl.innerHTML = ""; contentEl.classList.remove("typing-indicator"); const fullText = await handleStreamingResponse(response, assistantMsgEl, contentEl); // Save to history chatHistory.push({ role: "user", content: text }); chatHistory.push({ role: "assistant", content: fullText }); } catch (err) { contentEl.innerHTML = `Connection Error: ${err.message}`; } }); });