| const QA_FILE = "questions_answers.json"; |
|
|
| |
| |
| |
| const API_URL = "http://localhost:5000"; |
|
|
| const listEl = document.getElementById("question-list"); |
| const logEl = document.getElementById("log"); |
| const customInput = document.getElementById("custom-input"); |
| const customSubmit = document.getElementById("custom-submit"); |
|
|
| let faq = []; |
| let hintCleared = false; |
|
|
| async function loadFaq() { |
| try { |
| const res = await fetch(QA_FILE, { cache: "no-store" }); |
| if (!res.ok) throw new Error("fetch failed: " + res.status); |
| faq = await res.json(); |
| } catch (err) { |
| listEl.innerHTML = `<div class="log-hint"> |
| // could not load ${QA_FILE} (${err.message}). Make sure it's uploaded |
| alongside index.html in this Space. |
| </div>`; |
| return; |
| } |
| renderQuestions(); |
| } |
|
|
| function renderQuestions() { |
| listEl.innerHTML = ""; |
| faq.forEach((item, i) => { |
| const btn = document.createElement("button"); |
| btn.className = "q-btn"; |
| btn.type = "button"; |
| btn.textContent = item.question; |
| btn.addEventListener("click", () => runQuestion(item, btn)); |
| listEl.appendChild(btn); |
| }); |
| } |
|
|
| function runQuestion(item, btnEl) { |
| document.querySelectorAll(".q-btn").forEach(b => b.classList.remove("active")); |
| btnEl.classList.add("active"); |
|
|
| const aLine = addLogEntry(item.question); |
| typeAnswer(aLine, item.answer); |
| } |
|
|
| function typeAnswer(el, text) { |
| const cursor = document.createElement("span"); |
| cursor.className = "cursor"; |
|
|
| let i = 0; |
| const speed = 14; |
|
|
| function step() { |
| if (i <= text.length) { |
| el.textContent = text.slice(0, i); |
| el.appendChild(cursor); |
| i++; |
| setTimeout(step, speed); |
| } else { |
| cursor.remove(); |
| } |
| } |
| step(); |
| } |
|
|
| function addLogEntry(questionText) { |
| if (!hintCleared) { |
| logEl.innerHTML = ""; |
| hintCleared = true; |
| } |
| document.querySelectorAll(".q-btn").forEach(b => b.classList.remove("active")); |
|
|
| const entry = document.createElement("div"); |
| entry.className = "log-entry"; |
|
|
| const qLine = document.createElement("div"); |
| qLine.className = "log-q"; |
| qLine.textContent = questionText; |
|
|
| const aLine = document.createElement("div"); |
| aLine.className = "log-a"; |
|
|
| entry.appendChild(qLine); |
| entry.appendChild(aLine); |
| logEl.appendChild(entry); |
| entry.scrollIntoView({ behavior: "smooth", block: "end" }); |
| return aLine; |
| } |
|
|
| async function askCustom() { |
| const question = customInput.value.trim(); |
| if (!question) return; |
|
|
| customSubmit.disabled = true; |
| customInput.disabled = true; |
|
|
| const aLine = addLogEntry(question); |
| aLine.textContent = "generating..."; |
|
|
| try { |
| const res = await fetch(`${API_URL}/generate`, { |
| method: "POST", |
| headers: { "Content-Type": "application/json" }, |
| body: JSON.stringify({ question }), |
| }); |
| const data = await res.json(); |
|
|
| aLine.textContent = ""; |
| if (!res.ok) { |
| aLine.classList.add("error"); |
| typeAnswer(aLine, `error: ${data.error || res.statusText}`); |
| } else { |
| typeAnswer(aLine, data.answer); |
| } |
| } catch (err) { |
| aLine.textContent = ""; |
| aLine.classList.add("error"); |
| typeAnswer(aLine, `could not reach backend at ${API_URL} (${err.message})`); |
| } finally { |
| customSubmit.disabled = false; |
| customInput.disabled = false; |
| customInput.value = ""; |
| customInput.focus(); |
| } |
| } |
|
|
| customSubmit.addEventListener("click", askCustom); |
| customInput.addEventListener("keydown", (e) => { |
| if (e.key === "Enter") askCustom(); |
| }); |
|
|
| loadFaq(); |
|
|