analyzer / static /script.js
GLAkavya's picture
Update static/script.js
2042ce5 verified
const form = document.getElementById("analyze-form");
const statusBox = document.getElementById("status");
const metaBox = document.getElementById("meta");
const mHashtag = document.getElementById("m-hashtag");
const mGemini = document.getElementById("m-gemini");
const mFallback = document.getElementById("m-fallback");
const mModels = document.getElementById("m-models");
const pieDiv = document.getElementById("pie");
const lineDiv = document.getElementById("line");
const tableDiv = document.getElementById("table");
// Parallax cursor
const cursor = document.getElementById("parallax-cursor");
window.addEventListener("mousemove", (e) => {
const x = e.clientX, y = e.clientY;
cursor.style.opacity = ".9";
cursor.style.left = x + "px";
cursor.style.top = y + "px";
});
// Helpers
function fmtPct(n){ return (Math.round(n * 100) / 100).toFixed(2); }
function renderMeta(meta) {
mHashtag.textContent = meta.hashtag;
mGemini.textContent = `Gemini: ${meta.generated_by.gemini}`;
mFallback.textContent = `Fallback: ${meta.generated_by.fallback}`;
mModels.textContent = `Gen: ${meta.model.generation} • Sentiment: ${meta.model.sentiment}`;
// meta fade-in animation
metaBox.style.opacity = "0";
metaBox.style.transform = "translateY(10px)";
requestAnimationFrame(() => {
metaBox.style.transition = "all .6s ease";
metaBox.style.opacity = "1";
metaBox.style.transform = "translateY(0)";
});
}
function renderPie(percent) {
const data = [{
values: [percent.positive, percent.neutral, percent.negative],
labels: ['Positive', 'Neutral', 'Negative'],
type: 'pie',
textinfo: 'label+percent',
hoverinfo: 'label+percent',
hole: .35
}];
const layout = {
paper_bgcolor: 'rgba(0,0,0,0)',
plot_bgcolor: 'rgba(0,0,0,0)',
font: {color: '#eaf2ff'},
margin: {l: 4, r: 4, t: 0, b: 0},
showlegend: false,
transition: {duration: 500, easing: "cubic-in-out"}
};
Plotly.newPlot(pieDiv, data, layout, {displayModeBar:false, responsive:true}).then(() => {
pieDiv.style.opacity = "0";
pieDiv.style.transform = "scale(0.9)";
requestAnimationFrame(() => {
pieDiv.style.transition = "all .6s ease";
pieDiv.style.opacity = "1";
pieDiv.style.transform = "scale(1)";
});
});
}
function renderLine(rolling) {
const data = [{
x: [...Array(rolling.length).keys()].map(i => i+1),
y: rolling,
type: 'scatter',
mode: 'lines+markers',
line: {shape: 'spline', smoothing: 1.3}
}];
const layout = {
paper_bgcolor: 'rgba(0,0,0,0)',
plot_bgcolor: 'rgba(0,0,0,0)',
font: {color: '#eaf2ff'},
margin: {l: 30, r: 10, t: 0, b: 24},
yaxis: {range:[0,1], tickformat: '.0%'},
transition: {duration: 600, easing: "cubic-in-out"}
};
Plotly.newPlot(lineDiv, data, layout, {displayModeBar:false, responsive:true}).then(() => {
lineDiv.style.opacity = "0";
lineDiv.style.transform = "translateY(20px)";
requestAnimationFrame(() => {
lineDiv.style.transition = "all .7s ease";
lineDiv.style.opacity = "1";
lineDiv.style.transform = "translateY(0)";
});
});
}
function renderTable(rows) {
tableDiv.innerHTML = "";
rows.forEach((r, i) => {
const row = document.createElement("div");
row.className = "row";
// text
const c1 = document.createElement("div");
c1.className = "cell";
c1.textContent = r.text;
// source chip
const c2 = document.createElement("div");
c2.className = "cell";
const chip = document.createElement("span");
chip.className = "chip " + (r.source === "gemini" ? "chip-gemini" : "chip-fallback");
chip.textContent = r.source === "gemini" ? "Gemini" : "Fallback";
c2.appendChild(chip);
// sentiment badge
const c3 = document.createElement("div");
c3.className = "cell";
const badge = document.createElement("span");
const s = r.sentiment;
badge.className = "badge " + (s === "POSITIVE" ? "pos" : s === "NEGATIVE" ? "neg" : "neu");
badge.textContent = s + " " + (r.score.toFixed(2));
c3.appendChild(badge);
row.appendChild(c1);
row.appendChild(c2);
row.appendChild(c3);
// add animation
row.style.opacity = "0";
row.style.transform = "translateX(-15px)";
setTimeout(() => {
row.style.transition = "all .4s ease";
row.style.opacity = "1";
row.style.transform = "translateX(0)";
}, 100 * i);
tableDiv.appendChild(row);
});
}
form.addEventListener("submit", async (e) => {
e.preventDefault();
const hashtag = document.getElementById("hashtag").value.trim();
const count = parseInt(document.getElementById("count").value || "20", 10);
if(!hashtag){
alert("Please enter a hashtag (e.g., #gla)");
return;
}
statusBox.classList.remove("hidden");
metaBox.classList.add("hidden");
try {
const resp = await fetch("/api/analyze", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({hashtag, count})
});
if(!resp.ok){
const err = await resp.json().catch(()=>({}));
throw new Error(err.error || `HTTP ${resp.status}`);
}
const data = await resp.json();
// META
renderMeta(data.meta);
metaBox.classList.remove("hidden");
// CHARTS
renderPie(data.aggregate.percent);
renderLine(data.aggregate.rolling);
// TABLE
renderTable(data.rows);
} catch (err) {
console.error(err);
alert("Failed: " + err.message);
} finally {
statusBox.classList.add("hidden");
}
});