noranisa commited on
Commit
7ac39fb
Β·
verified Β·
1 Parent(s): 5cb0ade

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +180 -120
templates/index.html CHANGED
@@ -2,16 +2,17 @@
2
  <html lang="id">
3
  <head>
4
  <meta charset="UTF-8">
5
- <title>AI Sentiment Dashboard</title>
6
 
7
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
8
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
 
9
 
10
  <style>
11
  body { background:#0f172a; color:white; }
12
 
13
  .sidebar {
14
- width:230px;
15
  height:100vh;
16
  position:fixed;
17
  background:#111827;
@@ -19,7 +20,7 @@ body { background:#0f172a; color:white; }
19
  }
20
 
21
  .main {
22
- margin-left:250px;
23
  padding:20px;
24
  }
25
 
@@ -37,7 +38,7 @@ table { font-size:13px; }
37
 
38
  <!-- πŸ”₯ SIDEBAR -->
39
  <div class="sidebar">
40
- <h4>πŸ”₯ Dashboard</h4>
41
 
42
  <input id="keyword" class="form-control mt-3" placeholder="Masukkan keyword">
43
 
@@ -47,37 +48,32 @@ table { font-size:13px; }
47
  <input type="radio" name="source" value="reddit"> Reddit
48
  </div>
49
 
50
- <button onclick="runAnalysis()" class="btn btn-primary mt-3 w-100">
51
- Analisis
52
- </button>
53
 
54
  <hr>
55
 
56
- <h6>Filter Sentimen</h6>
57
  <button onclick="filterData('All')" class="btn btn-dark btn-sm w-100 mt-1">All</button>
58
  <button onclick="filterData('Positive')" class="btn btn-success btn-sm w-100 mt-1">Positive</button>
59
  <button onclick="filterData('Neutral')" class="btn btn-secondary btn-sm w-100 mt-1">Neutral</button>
60
  <button onclick="filterData('Negative')" class="btn btn-danger btn-sm w-100 mt-1">Negative</button>
61
 
62
  <hr>
63
-
64
  <a href="/download" class="btn btn-success w-100">⬇ Download CSV</a>
65
  </div>
66
 
67
  <!-- πŸ”₯ MAIN -->
68
  <div class="main">
69
 
70
- <h3>πŸ“Š AI Sentiment Dashboard</h3>
71
 
72
- <!-- LOADING -->
73
  <div id="loading" style="display:none;">
74
  <div class="spinner-border text-light"></div>
75
- <p>Memproses data...</p>
76
  </div>
77
 
78
- <!-- CHART + WORD -->
79
  <div class="row mt-3">
80
-
81
  <div class="col-md-6">
82
  <div class="card p-3">
83
  <h5>Distribusi Sentimen</h5>
@@ -87,213 +83,277 @@ table { font-size:13px; }
87
 
88
  <div class="col-md-6">
89
  <div class="card p-3">
90
- <h5>Top Kata</h5>
91
  <ul id="topWords"></ul>
92
  </div>
93
  </div>
94
-
95
  </div>
96
 
97
- <!-- HEATMAP + WORDCLOUD -->
98
  <div class="row mt-3">
99
-
100
  <div class="col-md-6">
101
  <div class="card p-3">
102
- <h5>πŸ”₯ Heatmap</h5>
103
- <img id="heatmap" src="/static/heatmap.png" width="100%">
104
  </div>
105
  </div>
106
 
107
  <div class="col-md-6">
108
  <div class="card p-3">
109
- <h5>☁️ WordCloud</h5>
110
- <img id="wordcloud" src="/static/wordcloud.png" width="100%">
111
  </div>
112
  </div>
113
-
114
  </div>
115
 
116
- <!-- TIMELINE -->
117
  <div class="card mt-3 p-3">
118
- <h5>πŸ“ˆ Sentiment Timeline</h5>
119
- <img id="timeline" src="/static/timeline.png" width="100%">
120
  </div>
121
 
122
  <!-- TOPIC -->
123
  <div class="card mt-3 p-3">
124
- <h5>🧠 Topic Modeling</h5>
125
  <ul id="topics"></ul>
126
  </div>
127
 
128
  <!-- CLUSTER -->
129
  <div class="card mt-3 p-3">
130
- <h5>🧠 Clustering Opini</h5>
131
  <div id="clusters"></div>
132
  </div>
133
 
134
  <!-- HOAX -->
135
  <div class="card mt-3 p-3">
136
- <h5>🚨 Deteksi Hoax</h5>
137
- <div id="hoaxBox"></div>
138
  </div>
139
 
140
- <!-- INSIGHT -->
141
  <div class="card mt-3 p-3">
142
- <h5>πŸ€– AI Insight</h5>
143
- <pre id="insightBox"></pre>
144
  </div>
145
 
146
- <!-- TABLE -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  <div class="card mt-3 p-3">
148
- <h5>Data Komentar</h5>
 
 
149
 
150
- <table class="table table-dark table-striped">
 
 
 
151
  <thead>
152
- <tr><th>No</th><th>Text</th><th>Sentiment</th><th>Source</th></tr>
153
  </thead>
154
  <tbody id="table"></tbody>
155
  </table>
156
-
157
  </div>
158
 
159
  </div>
160
 
161
  <script>
162
 
163
- let allData = [];
164
  let chart;
165
 
166
- // πŸ”₯ ANALISIS
167
- function runAnalysis() {
168
- const keyword = document.getElementById("keyword").value;
169
- const source = document.querySelector('input[name="source"]:checked').value;
170
 
171
- document.getElementById("loading").style.display = "block";
172
 
173
- fetch('/analyze', {
174
- method:'POST',
175
- headers:{'Content-Type':'application/json'},
176
  body:JSON.stringify({keyword,source})
177
  })
178
  .then(res=>res.json())
179
  .then(res=>{
180
- allData = res.data;
181
  updateUI(res);
182
- document.getElementById("loading").style.display = "none";
183
  });
184
  }
185
 
186
  // πŸ”₯ UPDATE UI
187
- function updateUI(res) {
188
  renderTable(res.data);
189
  renderChart(res.data);
190
  renderTopWords(res.top_words);
191
  renderTopics(res.topics);
192
- renderInsight(res.insight);
193
  renderClusters(res.clusters);
194
  renderHoax(res.hoax);
195
-
196
- // πŸ”₯ refresh image (anti cache)
197
- document.getElementById("wordcloud").src = "/static/wordcloud.png?"+Math.random();
198
- document.getElementById("heatmap").src = "/static/heatmap.png?"+Math.random();
199
- document.getElementById("timeline").src = "/static/timeline.png?"+Math.random();
 
 
 
 
 
 
200
  }
201
 
202
  // πŸ”₯ TABLE
203
- function renderTable(data) {
204
- const table = document.getElementById("table");
205
- table.innerHTML="";
206
-
207
  data.forEach((d,i)=>{
208
- table.innerHTML += `
209
- <tr>
210
- <td>${i+1}</td>
211
- <td>${d.text}</td>
212
- <td>${d.sentiment}</td>
213
- <td>${d.source}</td>
214
- </tr>`;
215
  });
 
216
  }
217
 
218
  // πŸ”₯ CHART
219
- function renderChart(data) {
220
- let counts = {Positive:0, Neutral:0, Negative:0};
221
  data.forEach(d=>counts[d.sentiment]++);
222
 
223
  if(chart) chart.destroy();
224
 
225
- chart = new Chart(document.getElementById("chart"), {
226
- type:'pie',
227
- data:{
228
- labels:Object.keys(counts),
229
- datasets:[{data:Object.values(counts)}]
230
- }
231
  });
232
  }
233
 
234
- // πŸ”₯ FILTER
235
- function filterData(type){
236
- if(type==="All"){
237
- renderTable(allData);
238
- renderChart(allData);
239
- } else {
240
- const filtered = allData.filter(d=>d.sentiment===type);
241
- renderTable(filtered);
242
- renderChart(filtered);
243
- }
244
- }
245
-
246
- // πŸ”₯ TOP WORDS
247
  function renderTopWords(words){
248
- const el = document.getElementById("topWords");
249
- el.innerHTML="";
250
- words.forEach(w=>{
251
- el.innerHTML += `<li>${w.word} (${w.count})</li>`;
252
- });
253
  }
254
 
255
  // πŸ”₯ TOPIC
256
  function renderTopics(topics){
257
- const el = document.getElementById("topics");
258
- el.innerHTML="";
259
- topics.forEach((t,i)=>{
260
- el.innerHTML += `<li><b>Topik ${i+1}:</b> ${t.join(", ")}</li>`;
261
- });
262
- }
263
-
264
- // πŸ”₯ INSIGHT
265
- function renderInsight(text){
266
- document.getElementById("insightBox").innerText = text;
267
  }
268
 
269
  // πŸ”₯ CLUSTER
270
- function renderClusters(clusters){
271
- const el = document.getElementById("clusters");
272
- el.innerHTML="";
273
- clusters.forEach(c=>{
274
- el.innerHTML += `<b>Cluster ${c.cluster}</b><ul>` +
275
- c.samples.map(s=>`<li>${s}</li>`).join("") +
276
- "</ul>";
277
  });
 
278
  }
279
 
280
  // πŸ”₯ HOAX
281
  function renderHoax(data){
282
- const el = document.getElementById("hoaxBox");
283
- el.innerHTML="";
284
- data.slice(0,10).forEach(d=>{
285
- el.innerHTML += `
286
- <p><b>${d.label}</b> (score: ${d.score})<br>${d.text}</p><hr>`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  });
288
  }
289
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  // πŸ”₯ AUTO REFRESH
291
  setInterval(()=>{
292
- const keyword = document.getElementById("keyword").value;
293
- if(keyword){
294
- runAnalysis();
295
- }
296
- }, 5000);
297
 
298
  </script>
299
 
 
2
  <html lang="id">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <title>AI Social Media Intelligence</title>
6
 
7
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
8
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
+ <script src="https://d3js.org/d3.v7.min.js"></script>
10
 
11
  <style>
12
  body { background:#0f172a; color:white; }
13
 
14
  .sidebar {
15
+ width:240px;
16
  height:100vh;
17
  position:fixed;
18
  background:#111827;
 
20
  }
21
 
22
  .main {
23
+ margin-left:260px;
24
  padding:20px;
25
  }
26
 
 
38
 
39
  <!-- πŸ”₯ SIDEBAR -->
40
  <div class="sidebar">
41
+ <h4>πŸ”₯ AI Dashboard</h4>
42
 
43
  <input id="keyword" class="form-control mt-3" placeholder="Masukkan keyword">
44
 
 
48
  <input type="radio" name="source" value="reddit"> Reddit
49
  </div>
50
 
51
+ <button onclick="runAnalysis()" class="btn btn-primary mt-3 w-100">Analisis</button>
 
 
52
 
53
  <hr>
54
 
55
+ <h6>Filter</h6>
56
  <button onclick="filterData('All')" class="btn btn-dark btn-sm w-100 mt-1">All</button>
57
  <button onclick="filterData('Positive')" class="btn btn-success btn-sm w-100 mt-1">Positive</button>
58
  <button onclick="filterData('Neutral')" class="btn btn-secondary btn-sm w-100 mt-1">Neutral</button>
59
  <button onclick="filterData('Negative')" class="btn btn-danger btn-sm w-100 mt-1">Negative</button>
60
 
61
  <hr>
 
62
  <a href="/download" class="btn btn-success w-100">⬇ Download CSV</a>
63
  </div>
64
 
65
  <!-- πŸ”₯ MAIN -->
66
  <div class="main">
67
 
68
+ <h3>πŸ“Š AI Social Media Intelligence</h3>
69
 
 
70
  <div id="loading" style="display:none;">
71
  <div class="spinner-border text-light"></div>
72
+ <p>Loading...</p>
73
  </div>
74
 
75
+ <!-- CHART -->
76
  <div class="row mt-3">
 
77
  <div class="col-md-6">
78
  <div class="card p-3">
79
  <h5>Distribusi Sentimen</h5>
 
83
 
84
  <div class="col-md-6">
85
  <div class="card p-3">
86
+ <h5>Top Words</h5>
87
  <ul id="topWords"></ul>
88
  </div>
89
  </div>
 
90
  </div>
91
 
92
+ <!-- IMAGE -->
93
  <div class="row mt-3">
 
94
  <div class="col-md-6">
95
  <div class="card p-3">
96
+ <h5>Heatmap</h5>
97
+ <img id="heatmap" width="100%">
98
  </div>
99
  </div>
100
 
101
  <div class="col-md-6">
102
  <div class="card p-3">
103
+ <h5>Wordcloud</h5>
104
+ <img id="wordcloud" width="100%">
105
  </div>
106
  </div>
 
107
  </div>
108
 
 
109
  <div class="card mt-3 p-3">
110
+ <h5>Timeline</h5>
111
+ <img id="timeline" width="100%">
112
  </div>
113
 
114
  <!-- TOPIC -->
115
  <div class="card mt-3 p-3">
116
+ <h5>Topic Modeling</h5>
117
  <ul id="topics"></ul>
118
  </div>
119
 
120
  <!-- CLUSTER -->
121
  <div class="card mt-3 p-3">
122
+ <h5>Clustering</h5>
123
  <div id="clusters"></div>
124
  </div>
125
 
126
  <!-- HOAX -->
127
  <div class="card mt-3 p-3">
128
+ <h5>Hoax Detection</h5>
129
+ <div id="hoax"></div>
130
  </div>
131
 
132
+ <!-- NETWORK -->
133
  <div class="card mt-3 p-3">
134
+ <h5>Network Graph</h5>
135
+ <div id="graph"></div>
136
  </div>
137
 
138
+ <!-- BOT NETWORK -->
139
+ <div class="card mt-3 p-3">
140
+ <h5>Bot Network</h5>
141
+ <div id="botGraph"></div>
142
+ </div>
143
+
144
+ <div class="card mt-3 p-3">
145
+ <h5>Bot List</h5>
146
+ <div id="bots"></div>
147
+ </div>
148
+
149
+ <!-- GNN -->
150
+ <div class="card mt-3 p-3">
151
+ <h5>GNN Result</h5>
152
+ <div id="gnn"></div>
153
+ </div>
154
+
155
+ <!-- BERT BOT -->
156
+ <div class="card mt-3 p-3">
157
+ <h5>BERT Bot Detection</h5>
158
+ <div id="botBert"></div>
159
+ </div>
160
+
161
+ <!-- FAKE NEWS -->
162
+ <div class="card mt-3 p-3">
163
+ <h5>Fake News Detection</h5>
164
+ <div id="fakeNews"></div>
165
+ </div>
166
+
167
+ <!-- TREND -->
168
  <div class="card mt-3 p-3">
169
+ <h5>Trend</h5>
170
+ <h4 id="trend"></h4>
171
+ </div>
172
 
173
+ <!-- TABLE -->
174
+ <div class="card mt-3 p-3">
175
+ <h5>Data</h5>
176
+ <table class="table table-dark">
177
  <thead>
178
+ <tr><th>No</th><th>Text</th><th>Sentiment</th></tr>
179
  </thead>
180
  <tbody id="table"></tbody>
181
  </table>
 
182
  </div>
183
 
184
  </div>
185
 
186
  <script>
187
 
188
+ let allData=[];
189
  let chart;
190
 
191
+ // πŸ”₯ ANALYSIS
192
+ function runAnalysis(){
193
+ const keyword=document.getElementById("keyword").value;
194
+ const source=document.querySelector('input[name="source"]:checked').value;
195
 
196
+ document.getElementById("loading").style.display="block";
197
 
198
+ fetch("/analyze",{
199
+ method:"POST",
200
+ headers:{"Content-Type":"application/json"},
201
  body:JSON.stringify({keyword,source})
202
  })
203
  .then(res=>res.json())
204
  .then(res=>{
205
+ allData=res.data;
206
  updateUI(res);
207
+ document.getElementById("loading").style.display="none";
208
  });
209
  }
210
 
211
  // πŸ”₯ UPDATE UI
212
+ function updateUI(res){
213
  renderTable(res.data);
214
  renderChart(res.data);
215
  renderTopWords(res.top_words);
216
  renderTopics(res.topics);
 
217
  renderClusters(res.clusters);
218
  renderHoax(res.hoax);
219
+ renderGraph(res.network);
220
+ renderBotNetwork(res.bot_network);
221
+ renderBots(res.bot_network.bots);
222
+ renderGNN(res.gnn);
223
+ renderBotBert(res.bot_bert);
224
+ renderFakeNews(res.fake_news);
225
+ document.getElementById("trend").innerText=res.trend;
226
+
227
+ document.getElementById("wordcloud").src="/static/wordcloud.png?"+Math.random();
228
+ document.getElementById("heatmap").src="/static/heatmap.png?"+Math.random();
229
+ document.getElementById("timeline").src="/static/timeline.png?"+Math.random();
230
  }
231
 
232
  // πŸ”₯ TABLE
233
+ function renderTable(data){
234
+ let html="";
 
 
235
  data.forEach((d,i)=>{
236
+ html+=`<tr><td>${i+1}</td><td>${d.text}</td><td>${d.sentiment}</td></tr>`;
 
 
 
 
 
 
237
  });
238
+ document.getElementById("table").innerHTML=html;
239
  }
240
 
241
  // πŸ”₯ CHART
242
+ function renderChart(data){
243
+ let counts={Positive:0,Neutral:0,Negative:0};
244
  data.forEach(d=>counts[d.sentiment]++);
245
 
246
  if(chart) chart.destroy();
247
 
248
+ chart=new Chart(document.getElementById("chart"),{
249
+ type:"pie",
250
+ data:{labels:Object.keys(counts),datasets:[{data:Object.values(counts)}]}
 
 
 
251
  });
252
  }
253
 
254
+ // πŸ”₯ TOP WORD
 
 
 
 
 
 
 
 
 
 
 
 
255
  function renderTopWords(words){
256
+ let html="";
257
+ words.forEach(w=>html+=`<li>${w.word} (${w.count})</li>`);
258
+ document.getElementById("topWords").innerHTML=html;
 
 
259
  }
260
 
261
  // πŸ”₯ TOPIC
262
  function renderTopics(topics){
263
+ let html="";
264
+ topics.forEach(t=>html+=`<li>${t.join(", ")}</li>`);
265
+ document.getElementById("topics").innerHTML=html;
 
 
 
 
 
 
 
266
  }
267
 
268
  // πŸ”₯ CLUSTER
269
+ function renderClusters(data){
270
+ let html="";
271
+ data.forEach(c=>{
272
+ html+=`<b>Cluster ${c.cluster}</b><ul>`;
273
+ c.samples.forEach(s=>html+=`<li>${s}</li>`);
274
+ html+="</ul>";
 
275
  });
276
+ document.getElementById("clusters").innerHTML=html;
277
  }
278
 
279
  // πŸ”₯ HOAX
280
  function renderHoax(data){
281
+ let html="";
282
+ data.forEach(d=>html+=`<p>${d.label} - ${d.text}</p>`);
283
+ document.getElementById("hoax").innerHTML=html;
284
+ }
285
+
286
+ // πŸ”₯ NETWORK
287
+ function renderGraph(data){
288
+ const width=400,height=300;
289
+ document.getElementById("graph").innerHTML="";
290
+ const svg=d3.select("#graph").append("svg").attr("width",width).attr("height",height);
291
+
292
+ const nodes={};
293
+ data.forEach(d=>{
294
+ nodes[d.source]={id:d.source};
295
+ nodes[d.target]={id:d.target};
296
+ });
297
+
298
+ const simulation=d3.forceSimulation(Object.values(nodes))
299
+ .force("link",d3.forceLink(data).id(d=>d.id))
300
+ .force("charge",d3.forceManyBody().strength(-100))
301
+ .force("center",d3.forceCenter(width/2,height/2));
302
+
303
+ const link=svg.selectAll("line").data(data).enter().append("line");
304
+ const node=svg.selectAll("circle").data(Object.values(nodes)).enter().append("circle").attr("r",5);
305
+
306
+ simulation.on("tick",()=>{
307
+ link.attr("x1",d=>d.source.x).attr("y1",d=>d.source.y)
308
+ .attr("x2",d=>d.target.x).attr("y2",d=>d.target.y);
309
+ node.attr("cx",d=>d.x).attr("cy",d=>d.y);
310
  });
311
  }
312
 
313
+ // πŸ”₯ BOT GRAPH
314
+ function renderBotNetwork(graph){
315
+ renderGraph(graph.edges);
316
+ }
317
+
318
+ // πŸ”₯ BOT LIST
319
+ function renderBots(bots){
320
+ let html="";
321
+ bots.forEach(b=>html+=`<p>${b.score} - ${b.text}</p>`);
322
+ document.getElementById("bots").innerHTML=html;
323
+ }
324
+
325
+ // πŸ”₯ GNN
326
+ function renderGNN(data){
327
+ let html="";
328
+ data.forEach(d=>html+=`<p>Node ${d.node}: ${d.score}</p>`);
329
+ document.getElementById("gnn").innerHTML=html;
330
+ }
331
+
332
+ // πŸ”₯ BERT BOT
333
+ function renderBotBert(data){
334
+ let html="";
335
+ data.forEach(d=>html+=`<p>${d.label} (${d.score}) - ${d.text}</p>`);
336
+ document.getElementById("botBert").innerHTML=html;
337
+ }
338
+
339
+ // πŸ”₯ FAKE NEWS
340
+ function renderFakeNews(data){
341
+ let html="";
342
+ data.forEach(d=>html+=`<p>${d.label} (${d.score}) - ${d.text}</p>`);
343
+ document.getElementById("fakeNews").innerHTML=html;
344
+ }
345
+
346
+ // πŸ”₯ FILTER
347
+ function filterData(type){
348
+ if(type==="All") return renderTable(allData);
349
+ renderTable(allData.filter(d=>d.sentiment===type));
350
+ }
351
+
352
  // πŸ”₯ AUTO REFRESH
353
  setInterval(()=>{
354
+ const k=document.getElementById("keyword").value;
355
+ if(k) runAnalysis();
356
+ },5000);
 
 
357
 
358
  </script>
359