chirag1121 commited on
Commit
c4e7a27
Β·
verified Β·
1 Parent(s): 164d559

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -79
app.py CHANGED
@@ -24,7 +24,6 @@ MODEL_NAME = "jy46604790/Fake-News-Bert-Detect"
24
 
25
  # Source credibility database
26
  SOURCE_CREDIBILITY = {
27
- # High credibility (score: 0.9–1.0)
28
  "bbc.com": 0.97, "bbc.co.uk": 0.97,
29
  "reuters.com": 0.96, "apnews.com": 0.95,
30
  "theguardian.com": 0.93, "nytimes.com": 0.92,
@@ -35,12 +34,10 @@ SOURCE_CREDIBILITY = {
35
  "cdc.gov": 0.97, "gov.uk": 0.94,
36
  "thehindu.com": 0.88, "ndtv.com": 0.82,
37
  "hindustantimes.com": 0.80, "timesofindia.com": 0.79,
38
- # Medium credibility (0.5–0.8)
39
  "cnn.com": 0.78, "foxnews.com": 0.65,
40
  "huffpost.com": 0.70, "buzzfeed.com": 0.62,
41
  "vice.com": 0.68, "vox.com": 0.74,
42
  "medium.com": 0.52, "substack.com": 0.50,
43
- # Low credibility (< 0.5) β€” examples of known misinformation sites
44
  "infowars.com": 0.05, "naturalnews.com": 0.08,
45
  "beforeitsnews.com": 0.06, "worldnewsdailyreport.com": 0.04,
46
  "empirenews.net": 0.04, "theonion.com": 0.10,
@@ -80,7 +77,6 @@ def classify_text(text, tokenizer, model):
80
  outputs = model(**inputs)
81
  probs = torch.softmax(outputs.logits, dim=1).squeeze().numpy()
82
 
83
- # Model labels: 0 = FAKE, 1 = REAL (adjust if needed for your model)
84
  labels = model.config.id2label
85
  fake_idx = next((i for i, l in labels.items() if "fake" in l.lower() or "0" == str(i)), 0)
86
  real_idx = 1 - fake_idx
@@ -103,8 +99,7 @@ def get_source_credibility(url_or_domain):
103
  if domain in SOURCE_CREDIBILITY:
104
  score = SOURCE_CREDIBILITY[domain]
105
  else:
106
- # Heuristics for unknown sources
107
- score = 0.45 # default unknown
108
  if domain.endswith(".gov") or domain.endswith(".edu"):
109
  score = 0.90
110
  elif domain.endswith(".org"):
@@ -249,7 +244,6 @@ html, body, [class*="css"] {
249
  }
250
  .stApp { background: #050a14; }
251
 
252
- /* Hero banner */
253
  .hero {
254
  background: linear-gradient(135deg, #0f172a 0%, #1a0a2e 50%, #0f172a 100%);
255
  border: 1px solid #1e293b;
@@ -275,7 +269,6 @@ html, body, [class*="css"] {
275
  }
276
  .hero p { color: #94a3b8; font-size: 1.05rem; margin-top: 0.5rem; margin-bottom: 0; }
277
 
278
- /* Cards */
279
  .card {
280
  background: #0f172a;
281
  border: 1px solid #1e293b;
@@ -303,7 +296,6 @@ html, body, [class*="css"] {
303
  .fake-label { color: #ef4444; }
304
  .real-label { color: #22c55e; }
305
 
306
- /* Indicator pills */
307
  .indicator-pill {
308
  display: inline-block;
309
  background: #1e1030;
@@ -316,7 +308,6 @@ html, body, [class*="css"] {
316
  font-family: 'JetBrains Mono', monospace;
317
  }
318
 
319
- /* News cards */
320
  .news-card {
321
  background: #0f172a;
322
  border: 1px solid #1e293b;
@@ -329,13 +320,11 @@ html, body, [class*="css"] {
329
  .news-card h4 { color: #e2e8f0; font-size: 0.95rem; margin: 0 0 0.4rem 0; }
330
  .news-card p { color: #64748b; font-size: 0.82rem; margin: 0; }
331
 
332
- /* Sidebar */
333
  section[data-testid="stSidebar"] {
334
  background: #080d1a;
335
  border-right: 1px solid #1e293b;
336
  }
337
 
338
- /* Inputs */
339
  .stTextArea textarea, .stTextInput input {
340
  background: #0f172a !important;
341
  border: 1px solid #334155 !important;
@@ -357,13 +346,11 @@ section[data-testid="stSidebar"] {
357
  }
358
  .stButton > button:hover { opacity: 0.85 !important; }
359
 
360
- /* Section headers */
361
  .section-title {
362
  font-size: 0.75rem; font-weight: 700; letter-spacing: 3px;
363
  color: #6366f1; text-transform: uppercase; margin-bottom: 0.75rem;
364
  }
365
 
366
- /* Metric boxes */
367
  .metric-box {
368
  background: #0f172a;
369
  border: 1px solid #1e293b;
@@ -378,7 +365,7 @@ div[data-testid="stMetricValue"] { color: #818cf8 !important; font-family: 'Syne
378
  </style>
379
  """, unsafe_allow_html=True)
380
 
381
- # ── Sidebar ─────────────────────────────────
382
  with st.sidebar:
383
  st.markdown("## πŸ” FakeScope")
384
  st.markdown("---")
@@ -386,7 +373,7 @@ with st.sidebar:
386
  st.markdown("---")
387
  st.markdown("**About the Model**")
388
  st.caption(f"`{MODEL_NAME}`")
389
- st.caption("Fine-tuned RoBERTa β€” no local training required.")
390
  st.markdown("---")
391
  st.markdown("**Credibility DB**")
392
  st.caption(f"{len(SOURCE_CREDIBILITY)} known sources indexed.")
@@ -441,27 +428,34 @@ if mode == "πŸ“ Paste Article / Text":
441
  vcol1, vcol2, vcol3 = st.columns([1, 2, 1])
442
  with vcol2:
443
  if prediction == "FAKE":
444
- low_conf = confidence < 0.75
445
- warning = "<div style='color:#fbbf24;font-size:0.85rem;margin-top:0.5rem'>⚠ Low confidence β€” verify manually before concluding</div>" if low_conf else ""
446
- st.markdown(
447
- f"""
448
- <div class="verdict-fake">
449
- <div class="verdict-label fake-label">⚠ FAKE NEWS</div>
450
- <div style="color:#94a3b8;margin-top:0.4rem;font-size:0.95rem;">
451
- Confidence: <b style="color:#f8fafc">{confidence*100:.1f}%</b>
452
- </div>
453
- {warning}
454
- </div>""",
455
- unsafe_allow_html=True,
456
- )
 
 
 
 
457
  else:
458
- st.markdown(f"""
459
- <div class="verdict-real">
460
- <div class="verdict-label real-label">βœ… LIKELY REAL</div>
461
- <div style="color:#94a3b8;margin-top:0.4rem;font-size:0.95rem;">
462
- Confidence: <b style="color:#f8fafc">{confidence*100:.1f}%</b>
463
- </div>
464
- </div>""", unsafe_allow_html=True)
 
 
 
465
 
466
  st.markdown("<br>", unsafe_allow_html=True)
467
 
@@ -478,11 +472,16 @@ if mode == "πŸ“ Paste Article / Text":
478
 
479
  # ── Source Credibility ───────────────────
480
  st.markdown('<div class="section-title">Source Credibility Score</div>', unsafe_allow_html=True)
481
- st.markdown(f"""
482
- <div class="card">
483
- <span style="font-size:1.1rem">{cred_label}</span>
484
- <span style="color:#64748b;font-family:monospace;font-size:0.85rem;margin-left:1rem">{domain or 'Unknown domain'}</span>
485
- </div>""", unsafe_allow_html=True)
 
 
 
 
 
486
  st.plotly_chart(credibility_bar_chart(domain or "Unknown", cred_score),
487
  use_container_width=True, config={"displayModeBar": False})
488
 
@@ -503,9 +502,11 @@ if mode == "πŸ“ Paste Article / Text":
503
  if fake_prob > 0.85:
504
  reasons.append("Very high BERT fake-probability score (>85%)")
505
  if cred_score < 0.5:
506
- reasons.append(f"Source '{domain}' has very low credibility ({cred_score*100:.0f}/100)")
 
507
  if indicators:
508
- reasons.append(f"{len(indicators)} sensational/clickbait linguistic patterns found")
 
509
  if reasons:
510
  st.markdown("**Key reasons for FAKE classification:**")
511
  for r in reasons:
@@ -515,17 +516,25 @@ if mode == "πŸ“ Paste Article / Text":
515
  st.markdown('<div class="section-title">Analytics Summary</div>', unsafe_allow_html=True)
516
  m1, m2, m3, m4 = st.columns(4)
517
  with m1:
518
- st.markdown(f'<div class="metric-box"><div class="val">{fake_prob*100:.0f}%</div><div class="lbl">FAKE PROB</div></div>',
519
- unsafe_allow_html=True)
 
 
520
  with m2:
521
- st.markdown(f'<div class="metric-box"><div class="val">{real_prob*100:.0f}%</div><div class="lbl">REAL PROB</div></div>',
522
- unsafe_allow_html=True)
 
 
523
  with m3:
524
- st.markdown(f'<div class="metric-box"><div class="val">{cred_score*100:.0f}</div><div class="lbl">SOURCE SCORE</div></div>',
525
- unsafe_allow_html=True)
 
 
526
  with m4:
527
- st.markdown(f'<div class="metric-box"><div class="val">{len(indicators)}</div><div class="lbl">RED FLAGS</div></div>',
528
- unsafe_allow_html=True)
 
 
529
 
530
  # ════════════════════════════════════════════
531
  # MODE 2 β€” Live News Feed
@@ -578,7 +587,6 @@ else:
578
  progress.progress((i + 1) / len(articles))
579
  progress.empty()
580
 
581
- # Summary metrics
582
  fake_count = sum(1 for r in results if r["prediction"] == "FAKE")
583
  real_count = len(results) - fake_count
584
  avg_conf = np.mean([r["confidence"] for r in results]) * 100
@@ -588,19 +596,26 @@ else:
588
  unsafe_allow_html=True)
589
  sm1, sm2, sm3, sm4 = st.columns(4)
590
  with sm1:
591
- st.markdown(f'<div class="metric-box"><div class="val">{len(results)}</div><div class="lbl">ARTICLES</div></div>',
592
- unsafe_allow_html=True)
 
 
593
  with sm2:
594
- st.markdown(f'<div class="metric-box"><div class="val" style="color:#ef4444">{fake_count}</div><div class="lbl">FLAGGED FAKE</div></div>',
595
- unsafe_allow_html=True)
 
 
596
  with sm3:
597
- st.markdown(f'<div class="metric-box"><div class="val" style="color:#22c55e">{real_count}</div><div class="lbl">LIKELY REAL</div></div>',
598
- unsafe_allow_html=True)
 
 
599
  with sm4:
600
- st.markdown(f'<div class="metric-box"><div class="val">{avg_conf:.0f}%</div><div class="lbl">AVG CONFIDENCE</div></div>',
601
- unsafe_allow_html=True)
 
 
602
 
603
- # Batch chart
604
  st.markdown("<br>", unsafe_allow_html=True)
605
  titles_short = [r["title"][:45] + "…" if len(r["title"]) > 45 else r["title"]
606
  for r in results]
@@ -627,7 +642,6 @@ else:
627
  st.plotly_chart(fig_batch, use_container_width=True,
628
  config={"displayModeBar": False})
629
 
630
- # Individual cards
631
  st.markdown('<div class="section-title">Individual Article Results</div>',
632
  unsafe_allow_html=True)
633
  for r in results:
@@ -637,23 +651,26 @@ else:
637
  f'<span class="indicator-pill">{ind}</span>'
638
  for ind in r["indicators"][:2]
639
  ) if r["indicators"] else ""
640
- st.markdown(f"""
641
- <div class="news-card">
642
- <div style="display:flex;justify-content:space-between;align-items:flex-start">
643
- <h4>{r['title']}</h4>
644
- <span style="background:{badge_color}22;color:{badge_color};
645
- border:1px solid {badge_color};border-radius:99px;
646
- padding:0.2rem 0.8rem;font-size:0.8rem;font-weight:700;
647
- white-space:nowrap;margin-left:1rem">{badge_text}</span>
648
- </div>
649
- <p>πŸ“° {r['source']} &nbsp;Β·&nbsp; Confidence: {r['confidence']*100:.1f}%
650
- &nbsp;Β·&nbsp; Source credibility: {r['cred_label']}</p>
651
- {ind_html}
652
- <p style="margin-top:0.5rem"><a href="{r['url']}" target="_blank"
653
- style="color:#6366f1;font-size:0.8rem">Read original β†’</a></p>
654
- </div>""", unsafe_allow_html=True)
655
-
656
- # ── Footer ──────────────────────────────────
 
 
 
657
  st.markdown("---")
658
  st.markdown(
659
  '<p style="text-align:center;color:#334155;font-size:0.8rem">'
 
24
 
25
  # Source credibility database
26
  SOURCE_CREDIBILITY = {
 
27
  "bbc.com": 0.97, "bbc.co.uk": 0.97,
28
  "reuters.com": 0.96, "apnews.com": 0.95,
29
  "theguardian.com": 0.93, "nytimes.com": 0.92,
 
34
  "cdc.gov": 0.97, "gov.uk": 0.94,
35
  "thehindu.com": 0.88, "ndtv.com": 0.82,
36
  "hindustantimes.com": 0.80, "timesofindia.com": 0.79,
 
37
  "cnn.com": 0.78, "foxnews.com": 0.65,
38
  "huffpost.com": 0.70, "buzzfeed.com": 0.62,
39
  "vice.com": 0.68, "vox.com": 0.74,
40
  "medium.com": 0.52, "substack.com": 0.50,
 
41
  "infowars.com": 0.05, "naturalnews.com": 0.08,
42
  "beforeitsnews.com": 0.06, "worldnewsdailyreport.com": 0.04,
43
  "empirenews.net": 0.04, "theonion.com": 0.10,
 
77
  outputs = model(**inputs)
78
  probs = torch.softmax(outputs.logits, dim=1).squeeze().numpy()
79
 
 
80
  labels = model.config.id2label
81
  fake_idx = next((i for i, l in labels.items() if "fake" in l.lower() or "0" == str(i)), 0)
82
  real_idx = 1 - fake_idx
 
99
  if domain in SOURCE_CREDIBILITY:
100
  score = SOURCE_CREDIBILITY[domain]
101
  else:
102
+ score = 0.45
 
103
  if domain.endswith(".gov") or domain.endswith(".edu"):
104
  score = 0.90
105
  elif domain.endswith(".org"):
 
244
  }
245
  .stApp { background: #050a14; }
246
 
 
247
  .hero {
248
  background: linear-gradient(135deg, #0f172a 0%, #1a0a2e 50%, #0f172a 100%);
249
  border: 1px solid #1e293b;
 
269
  }
270
  .hero p { color: #94a3b8; font-size: 1.05rem; margin-top: 0.5rem; margin-bottom: 0; }
271
 
 
272
  .card {
273
  background: #0f172a;
274
  border: 1px solid #1e293b;
 
296
  .fake-label { color: #ef4444; }
297
  .real-label { color: #22c55e; }
298
 
 
299
  .indicator-pill {
300
  display: inline-block;
301
  background: #1e1030;
 
308
  font-family: 'JetBrains Mono', monospace;
309
  }
310
 
 
311
  .news-card {
312
  background: #0f172a;
313
  border: 1px solid #1e293b;
 
320
  .news-card h4 { color: #e2e8f0; font-size: 0.95rem; margin: 0 0 0.4rem 0; }
321
  .news-card p { color: #64748b; font-size: 0.82rem; margin: 0; }
322
 
 
323
  section[data-testid="stSidebar"] {
324
  background: #080d1a;
325
  border-right: 1px solid #1e293b;
326
  }
327
 
 
328
  .stTextArea textarea, .stTextInput input {
329
  background: #0f172a !important;
330
  border: 1px solid #334155 !important;
 
346
  }
347
  .stButton > button:hover { opacity: 0.85 !important; }
348
 
 
349
  .section-title {
350
  font-size: 0.75rem; font-weight: 700; letter-spacing: 3px;
351
  color: #6366f1; text-transform: uppercase; margin-bottom: 0.75rem;
352
  }
353
 
 
354
  .metric-box {
355
  background: #0f172a;
356
  border: 1px solid #1e293b;
 
365
  </style>
366
  """, unsafe_allow_html=True)
367
 
368
+ # ── Sidebar ──────────────────────────────────
369
  with st.sidebar:
370
  st.markdown("## πŸ” FakeScope")
371
  st.markdown("---")
 
373
  st.markdown("---")
374
  st.markdown("**About the Model**")
375
  st.caption(f"`{MODEL_NAME}`")
376
+ st.caption("Fine-tuned BERT β€” no local training required.")
377
  st.markdown("---")
378
  st.markdown("**Credibility DB**")
379
  st.caption(f"{len(SOURCE_CREDIBILITY)} known sources indexed.")
 
428
  vcol1, vcol2, vcol3 = st.columns([1, 2, 1])
429
  with vcol2:
430
  if prediction == "FAKE":
431
+ low_conf = confidence < 0.75
432
+ warning = (
433
+ "<div style='color:#fbbf24;font-size:0.85rem;margin-top:0.5rem'>"
434
+ "⚠ Low confidence β€” verify manually before concluding</div>"
435
+ if low_conf else ""
436
+ )
437
+ st.markdown(
438
+ f"""
439
+ <div class="verdict-fake">
440
+ <div class="verdict-label fake-label">⚠ FAKE NEWS</div>
441
+ <div style="color:#94a3b8;margin-top:0.4rem;font-size:0.95rem;">
442
+ Confidence: <b style="color:#f8fafc">{confidence*100:.1f}%</b>
443
+ </div>
444
+ {warning}
445
+ </div>""",
446
+ unsafe_allow_html=True,
447
+ )
448
  else:
449
+ st.markdown(
450
+ f"""
451
+ <div class="verdict-real">
452
+ <div class="verdict-label real-label">βœ… LIKELY REAL</div>
453
+ <div style="color:#94a3b8;margin-top:0.4rem;font-size:0.95rem;">
454
+ Confidence: <b style="color:#f8fafc">{confidence*100:.1f}%</b>
455
+ </div>
456
+ </div>""",
457
+ unsafe_allow_html=True,
458
+ )
459
 
460
  st.markdown("<br>", unsafe_allow_html=True)
461
 
 
472
 
473
  # ── Source Credibility ───────────────────
474
  st.markdown('<div class="section-title">Source Credibility Score</div>', unsafe_allow_html=True)
475
+ st.markdown(
476
+ f"""
477
+ <div class="card">
478
+ <span style="font-size:1.1rem">{cred_label}</span>
479
+ <span style="color:#64748b;font-family:monospace;font-size:0.85rem;margin-left:1rem">
480
+ {domain or 'Unknown domain'}
481
+ </span>
482
+ </div>""",
483
+ unsafe_allow_html=True,
484
+ )
485
  st.plotly_chart(credibility_bar_chart(domain or "Unknown", cred_score),
486
  use_container_width=True, config={"displayModeBar": False})
487
 
 
502
  if fake_prob > 0.85:
503
  reasons.append("Very high BERT fake-probability score (>85%)")
504
  if cred_score < 0.5:
505
+ reasons.append(
506
+ f"Source '{domain}' has very low credibility ({cred_score*100:.0f}/100)")
507
  if indicators:
508
+ reasons.append(
509
+ f"{len(indicators)} sensational/clickbait linguistic patterns found")
510
  if reasons:
511
  st.markdown("**Key reasons for FAKE classification:**")
512
  for r in reasons:
 
516
  st.markdown('<div class="section-title">Analytics Summary</div>', unsafe_allow_html=True)
517
  m1, m2, m3, m4 = st.columns(4)
518
  with m1:
519
+ st.markdown(
520
+ f'<div class="metric-box"><div class="val">{fake_prob*100:.0f}%</div>'
521
+ f'<div class="lbl">FAKE PROB</div></div>',
522
+ unsafe_allow_html=True)
523
  with m2:
524
+ st.markdown(
525
+ f'<div class="metric-box"><div class="val">{real_prob*100:.0f}%</div>'
526
+ f'<div class="lbl">REAL PROB</div></div>',
527
+ unsafe_allow_html=True)
528
  with m3:
529
+ st.markdown(
530
+ f'<div class="metric-box"><div class="val">{cred_score*100:.0f}</div>'
531
+ f'<div class="lbl">SOURCE SCORE</div></div>',
532
+ unsafe_allow_html=True)
533
  with m4:
534
+ st.markdown(
535
+ f'<div class="metric-box"><div class="val">{len(indicators)}</div>'
536
+ f'<div class="lbl">RED FLAGS</div></div>',
537
+ unsafe_allow_html=True)
538
 
539
  # ════════════════════════════════════════════
540
  # MODE 2 β€” Live News Feed
 
587
  progress.progress((i + 1) / len(articles))
588
  progress.empty()
589
 
 
590
  fake_count = sum(1 for r in results if r["prediction"] == "FAKE")
591
  real_count = len(results) - fake_count
592
  avg_conf = np.mean([r["confidence"] for r in results]) * 100
 
596
  unsafe_allow_html=True)
597
  sm1, sm2, sm3, sm4 = st.columns(4)
598
  with sm1:
599
+ st.markdown(
600
+ f'<div class="metric-box"><div class="val">{len(results)}</div>'
601
+ f'<div class="lbl">ARTICLES</div></div>',
602
+ unsafe_allow_html=True)
603
  with sm2:
604
+ st.markdown(
605
+ f'<div class="metric-box"><div class="val" style="color:#ef4444">{fake_count}</div>'
606
+ f'<div class="lbl">FLAGGED FAKE</div></div>',
607
+ unsafe_allow_html=True)
608
  with sm3:
609
+ st.markdown(
610
+ f'<div class="metric-box"><div class="val" style="color:#22c55e">{real_count}</div>'
611
+ f'<div class="lbl">LIKELY REAL</div></div>',
612
+ unsafe_allow_html=True)
613
  with sm4:
614
+ st.markdown(
615
+ f'<div class="metric-box"><div class="val">{avg_conf:.0f}%</div>'
616
+ f'<div class="lbl">AVG CONFIDENCE</div></div>',
617
+ unsafe_allow_html=True)
618
 
 
619
  st.markdown("<br>", unsafe_allow_html=True)
620
  titles_short = [r["title"][:45] + "…" if len(r["title"]) > 45 else r["title"]
621
  for r in results]
 
642
  st.plotly_chart(fig_batch, use_container_width=True,
643
  config={"displayModeBar": False})
644
 
 
645
  st.markdown('<div class="section-title">Individual Article Results</div>',
646
  unsafe_allow_html=True)
647
  for r in results:
 
651
  f'<span class="indicator-pill">{ind}</span>'
652
  for ind in r["indicators"][:2]
653
  ) if r["indicators"] else ""
654
+ st.markdown(
655
+ f"""
656
+ <div class="news-card">
657
+ <div style="display:flex;justify-content:space-between;align-items:flex-start">
658
+ <h4>{r['title']}</h4>
659
+ <span style="background:{badge_color}22;color:{badge_color};
660
+ border:1px solid {badge_color};border-radius:99px;
661
+ padding:0.2rem 0.8rem;font-size:0.8rem;font-weight:700;
662
+ white-space:nowrap;margin-left:1rem">{badge_text}</span>
663
+ </div>
664
+ <p>πŸ“° {r['source']} &nbsp;Β·&nbsp; Confidence: {r['confidence']*100:.1f}%
665
+ &nbsp;Β·&nbsp; Source credibility: {r['cred_label']}</p>
666
+ {ind_html}
667
+ <p style="margin-top:0.5rem"><a href="{r['url']}" target="_blank"
668
+ style="color:#6366f1;font-size:0.8rem">Read original β†’</a></p>
669
+ </div>""",
670
+ unsafe_allow_html=True,
671
+ )
672
+
673
+ # ── Footer ───────────────────────────────────
674
  st.markdown("---")
675
  st.markdown(
676
  '<p style="text-align:center;color:#334155;font-size:0.8rem">'