GLAkavya commited on
Commit
6af3f66
·
verified ·
1 Parent(s): 6264e90

Create script.js

Browse files
Files changed (1) hide show
  1. static/script.js +143 -0
static/script.js ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const form = document.getElementById("analyze-form");
2
+ const statusBox = document.getElementById("status");
3
+ const metaBox = document.getElementById("meta");
4
+
5
+ const mHashtag = document.getElementById("m-hashtag");
6
+ const mGemini = document.getElementById("m-gemini");
7
+ const mFallback = document.getElementById("m-fallback");
8
+ const mModels = document.getElementById("m-models");
9
+
10
+ const pieDiv = document.getElementById("pie");
11
+ const lineDiv = document.getElementById("line");
12
+ const tableDiv = document.getElementById("table");
13
+
14
+ // Parallax cursor
15
+ const cursor = document.getElementById("parallax-cursor");
16
+ window.addEventListener("mousemove", (e) => {
17
+ const x = e.clientX, y = e.clientY;
18
+ cursor.style.opacity = ".9";
19
+ cursor.style.left = x + "px";
20
+ cursor.style.top = y + "px";
21
+ });
22
+
23
+ // Helpers
24
+ function fmtPct(n){ return (Math.round(n * 100) / 100).toFixed(2); }
25
+
26
+ function renderMeta(meta) {
27
+ mHashtag.textContent = meta.hashtag;
28
+ mGemini.textContent = `Gemini: ${meta.generated_by.gemini}`;
29
+ mFallback.textContent = `Fallback: ${meta.generated_by.fallback}`;
30
+ mModels.textContent = `Gen: ${meta.model.generation} • Sentiment: ${meta.model.sentiment}`;
31
+ }
32
+
33
+ function renderPie(percent) {
34
+ const data = [{
35
+ values: [percent.positive, percent.neutral, percent.negative],
36
+ labels: ['Positive', 'Neutral', 'Negative'],
37
+ type: 'pie',
38
+ textinfo: 'label+percent',
39
+ hoverinfo: 'label+percent',
40
+ hole: .35
41
+ }];
42
+ const layout = {
43
+ paper_bgcolor: 'rgba(0,0,0,0)',
44
+ plot_bgcolor: 'rgba(0,0,0,0)',
45
+ font: {color: '#eaf2ff'},
46
+ margin: {l: 4, r: 4, t: 0, b: 0},
47
+ showlegend: false
48
+ };
49
+ Plotly.newPlot(pieDiv, data, layout, {displayModeBar:false, responsive:true});
50
+ }
51
+
52
+ function renderLine(rolling) {
53
+ const data = [{
54
+ x: [...Array(rolling.length).keys()].map(i => i+1),
55
+ y: rolling,
56
+ type: 'scatter',
57
+ mode: 'lines+markers'
58
+ }];
59
+ const layout = {
60
+ paper_bgcolor: 'rgba(0,0,0,0)',
61
+ plot_bgcolor: 'rgba(0,0,0,0)',
62
+ font: {color: '#eaf2ff'},
63
+ margin: {l: 30, r: 10, t: 0, b: 24},
64
+ yaxis: {range:[0,1], tickformat: '.0%'},
65
+ };
66
+ Plotly.newPlot(lineDiv, data, layout, {displayModeBar:false, responsive:true});
67
+ }
68
+
69
+ function renderTable(rows) {
70
+ tableDiv.innerHTML = "";
71
+ rows.forEach(r => {
72
+ const row = document.createElement("div");
73
+ row.className = "row";
74
+ // text
75
+ const c1 = document.createElement("div");
76
+ c1.className = "cell";
77
+ c1.textContent = r.text;
78
+ // source chip
79
+ const c2 = document.createElement("div");
80
+ c2.className = "cell";
81
+ const chip = document.createElement("span");
82
+ chip.className = "chip " + (r.source === "gemini" ? "chip-gemini" : "chip-fallback");
83
+ chip.textContent = r.source === "gemini" ? "Gemini" : "Fallback";
84
+ c2.appendChild(chip);
85
+ // sentiment badge
86
+ const c3 = document.createElement("div");
87
+ c3.className = "cell";
88
+ const badge = document.createElement("span");
89
+ const s = r.sentiment;
90
+ badge.className = "badge " + (s === "POSITIVE" ? "pos" : s === "NEGATIVE" ? "neg" : "neu");
91
+ badge.textContent = s + " " + (r.score.toFixed(2));
92
+ c3.appendChild(badge);
93
+
94
+ row.appendChild(c1);
95
+ row.appendChild(c2);
96
+ row.appendChild(c3);
97
+ tableDiv.appendChild(row);
98
+ });
99
+ }
100
+
101
+ form.addEventListener("submit", async (e) => {
102
+ e.preventDefault();
103
+ const hashtag = document.getElementById("hashtag").value.trim();
104
+ const count = parseInt(document.getElementById("count").value || "20", 10);
105
+
106
+ if(!hashtag){
107
+ alert("Please enter a hashtag (e.g., #gla)");
108
+ return;
109
+ }
110
+
111
+ statusBox.classList.remove("hidden");
112
+ metaBox.classList.add("hidden");
113
+
114
+ try {
115
+ const resp = await fetch("/api/analyze", {
116
+ method: "POST",
117
+ headers: {"Content-Type": "application/json"},
118
+ body: JSON.stringify({hashtag, count})
119
+ });
120
+ if(!resp.ok){
121
+ const err = await resp.json().catch(()=>({}));
122
+ throw new Error(err.error || `HTTP ${resp.status}`);
123
+ }
124
+ const data = await resp.json();
125
+
126
+ // META
127
+ renderMeta(data.meta);
128
+ metaBox.classList.remove("hidden");
129
+
130
+ // CHARTS
131
+ renderPie(data.aggregate.percent);
132
+ renderLine(data.aggregate.rolling);
133
+
134
+ // TABLE
135
+ renderTable(data.rows);
136
+
137
+ } catch (err) {
138
+ console.error(err);
139
+ alert("Failed: " + err.message);
140
+ } finally {
141
+ statusBox.classList.add("hidden");
142
+ }
143
+ });