/******************************* * Interview Q&A Frontend JS * *******************************/ // Elements const recordBtn = document.getElementById("record-button"); const questionEl = document.getElementById("question-output"); const answerEl = document.getElementById("answer-output"); // Typing animation util function typeEffect(el, text, speed = 30) { el.textContent = ""; let idx = 0; const timer = setInterval(() => { el.textContent += text.charAt(idx); idx++; if (idx >= text.length) clearInterval(timer); }, speed); } // Audio recording setup let mediaRecorder, chunks = []; // Initialise media data async function initMedia() { try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); mediaRecorder = new MediaRecorder(stream); // Continuously push available data mediaRecorder.ondataavailable = e => chunks.push(e.data); // Stop btn start write and send audio chunk mediaRecorder.onstop = async () => { const audioBlob = new Blob(chunks, { type: "audio/wav" }); chunks = []; // Build form data const form = new FormData(); form.append("file", audioBlob, "record.wav"); // UX feedback typeEffect(questionEl, "⌛ Transcribing…"); answerEl.textContent = ""; try { const res = await fetch("/voice-transcribe", { method: "POST", body: form }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); // render markdown after a small delay for dramatic effect typeEffect(questionEl, data.question || "[no speech detected]"); setTimeout(() => typeEffect(answerEl, data.answer || "[no answer]"), 500); } catch (err) { typeEffect(answerEl, "❌ " + err.message); } }; } catch (err) { alert("Microphone access denied – please allow permissions."); } } // Hold‑to‑record UX function bindRecordBtn() { if (!mediaRecorder) return; recordBtn.addEventListener("mousedown", () => mediaRecorder.start()); recordBtn.addEventListener("mouseup", () => mediaRecorder.stop()); // Touch devices recordBtn.addEventListener("touchstart", e => { e.preventDefault(); mediaRecorder.start(); }); recordBtn.addEventListener("touchend", e => { e.preventDefault(); mediaRecorder.stop(); }); } // Init on page load window.addEventListener("DOMContentLoaded", async () => { try { await initMedia(); bindRecordBtn(); } catch (e) { alert("Mic permission required"); } });