adnaan05 KhaqanNasir commited on
Commit
f184bba
·
verified ·
1 Parent(s): fa2ccb5

Update src/app.py (#16)

Browse files

- Update src/app.py (0bdecbdedf37f3eac4baae41d6bfcbb18c81068b)


Co-authored-by: Muhammad Khaqan Nasir <[email protected]>

Files changed (1) hide show
  1. src/app.py +172 -854
src/app.py CHANGED
@@ -35,577 +35,206 @@ from src.models.hybrid_model import HybridFakeNewsDetector
35
  from src.config.config import *
36
  from src.data.preprocessor import TextPreprocessor
37
 
38
- # Custom CSS for modern, enhanced styling
39
  st.markdown("""
40
  <style>
41
  /* Import Google Fonts */
42
- @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800;900&family=Inter:wght@300;400;500;600;700&display=swap');
43
-
44
  /* Global Styles */
45
  * {
46
  margin: 0;
47
  padding: 0;
48
  box-sizing: border-box;
49
  }
50
-
51
- .main {
52
- padding: 0 !important;
53
- max-width: 100% !important;
54
- }
55
-
56
  .stApp {
57
- font-family: 'Inter', 'Poppins', sans-serif;
58
- background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #6B73FF 100%);
59
  min-height: 100vh;
60
  color: #2d3748;
61
  }
62
-
63
  /* Hide Streamlit elements */
64
  #MainMenu {visibility: hidden;}
65
  footer {visibility: hidden;}
66
  .stDeployButton {display: none;}
67
  header {visibility: hidden;}
68
  .stApp > header {visibility: hidden;}
69
-
70
- /* Header Navigation */
71
- .header-nav {
72
- background: rgba(255, 255, 255, 0.95);
73
- backdrop-filter: blur(20px);
74
- border-bottom: 1px solid rgba(255, 255, 255, 0.2);
75
- padding: 1rem 2rem;
 
 
 
 
 
 
76
  position: sticky;
77
  top: 0;
78
  z-index: 1000;
79
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
80
  }
81
-
82
- .nav-brand {
83
- font-family: 'Poppins', sans-serif;
84
  font-size: 1.8rem;
85
- font-weight: 800;
86
- background: linear-gradient(135deg, #667eea, #764ba2);
87
- -webkit-background-clip: text;
88
- -webkit-text-fill-color: transparent;
89
- background-clip: text;
90
- display: inline-flex;
91
- align-items: center;
92
- gap: 0.5rem;
93
  }
94
-
95
  /* Hero Section */
96
- .hero-container {
97
- background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #6B73FF 100%);
98
- padding: 6rem 2rem;
99
- text-align: center;
100
- color: white;
101
- position: relative;
102
- overflow: hidden;
103
- }
104
-
105
- .hero-container::before {
106
- content: '';
107
- position: absolute;
108
- top: 0;
109
- left: 0;
110
- right: 0;
111
- bottom: 0;
112
- background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000"><defs><radialGradient id="a" cx="50%" cy="50%"><stop offset="0%" stop-color="%23fff" stop-opacity="0.1"/><stop offset="100%" stop-color="%23fff" stop-opacity="0"/></radialGradient></defs><circle cx="200" cy="200" r="100" fill="url(%23a)"/><circle cx="800" cy="300" r="150" fill="url(%23a)"/><circle cx="400" cy="700" r="120" fill="url(%23a)"/></svg>');
113
- pointer-events: none;
114
- }
115
-
116
- .hero-content {
117
- position: relative;
118
- z-index: 2;
119
- max-width: 800px;
120
- margin: 0 auto;
121
- }
122
-
123
- .hero-badge {
124
- display: inline-flex;
125
- align-items: center;
126
- gap: 0.5rem;
127
- background: rgba(255, 255, 255, 0.2);
128
- padding: 0.5rem 1.5rem;
129
- border-radius: 50px;
130
- font-size: 0.9rem;
131
- font-weight: 500;
132
- margin-bottom: 2rem;
133
- backdrop-filter: blur(10px);
134
- border: 1px solid rgba(255, 255, 255, 0.3);
135
- }
136
-
137
- .hero-title {
138
- font-family: 'Poppins', sans-serif;
139
- font-size: 4.5rem;
140
- font-weight: 900;
141
- margin-bottom: 1.5rem;
142
- text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
143
- background: linear-gradient(45deg, #fff, #e0e7ff, #fff);
144
- -webkit-background-clip: text;
145
- -webkit-text-fill-color: transparent;
146
- background-clip: text;
147
- line-height: 1.1;
148
- }
149
-
150
- .hero-subtitle {
151
- font-size: 1.4rem;
152
- font-weight: 400;
153
  margin-bottom: 3rem;
154
- opacity: 0.95;
155
- line-height: 1.7;
156
- max-width: 700px;
157
- margin-left: auto;
158
- margin-right: auto;
159
  }
160
-
161
- .hero-stats {
 
 
 
 
 
 
162
  display: flex;
 
163
  justify-content: center;
164
- gap: 3rem;
165
- margin-top: 2rem;
166
  }
167
-
168
- .stat-item {
169
- text-align: center;
 
 
 
170
  }
171
-
172
- .stat-number {
173
  font-size: 2.5rem;
174
  font-weight: 700;
175
- display: block;
176
- }
177
-
178
- .stat-label {
179
- font-size: 0.9rem;
180
- opacity: 0.8;
181
- }
182
-
183
- /* Features Section */
184
- .features-section {
185
- padding: 5rem 2rem;
186
- background: #f8fafc;
187
- position: relative;
188
- }
189
-
190
- .section-header {
191
- text-align: center;
192
- margin-bottom: 4rem;
193
- }
194
-
195
- .section-badge {
196
- display: inline-flex;
197
- align-items: center;
198
- gap: 0.5rem;
199
- background: linear-gradient(135deg, #667eea, #764ba2);
200
- color: white;
201
- padding: 0.5rem 1.5rem;
202
- border-radius: 50px;
203
- font-size: 0.85rem;
204
- font-weight: 600;
205
- margin-bottom: 1rem;
206
- text-transform: uppercase;
207
- letter-spacing: 0.5px;
208
- }
209
-
210
- .section-title {
211
- font-family: 'Poppins', sans-serif;
212
- font-size: 3rem;
213
- font-weight: 700;
214
  color: #1a202c;
215
  margin-bottom: 1rem;
216
- line-height: 1.2;
217
  }
218
-
219
- .section-description {
220
- font-size: 1.2rem;
221
  color: #4a5568;
222
- max-width: 600px;
223
- margin: 0 auto;
224
  line-height: 1.6;
225
  }
226
-
227
- .features-grid {
228
- display: grid;
229
- grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
230
- gap: 2rem;
231
- max-width: 1200px;
232
- margin: 0 auto;
233
- }
234
-
235
- .feature-card {
236
- background: white;
237
- padding: 2.5rem;
238
- border-radius: 20px;
239
  text-align: center;
240
- transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
241
- border: 1px solid #e2e8f0;
242
- position: relative;
243
- overflow: hidden;
244
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
245
- }
246
-
247
- .feature-card::before {
248
- content: '';
249
- position: absolute;
250
- top: 0;
251
- left: 0;
252
- right: 0;
253
- height: 4px;
254
- background: linear-gradient(135deg, #667eea, #764ba2);
255
- }
256
-
257
- .feature-card:hover {
258
- transform: translateY(-12px);
259
- box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
260
- border-color: #667eea;
261
- }
262
-
263
- .feature-icon {
264
- font-size: 3.5rem;
265
- margin-bottom: 1.5rem;
266
- display: block;
267
- filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.1));
268
  }
269
-
270
- .feature-title {
271
- font-family: 'Poppins', sans-serif;
272
- font-size: 1.4rem;
273
  font-weight: 600;
274
  color: #1a202c;
275
  margin-bottom: 1rem;
276
  }
277
-
278
- .feature-description {
 
279
  color: #4a5568;
280
  line-height: 1.6;
281
- font-size: 1rem;
282
- }
283
-
284
- /* Main Content Section */
285
- .main-content {
286
- background: white;
287
- margin: 3rem 2rem;
288
- padding: 4rem;
289
- border-radius: 24px;
290
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.1);
291
- position: relative;
292
- overflow: hidden;
293
- }
294
-
295
- .main-content::before {
296
- content: '';
297
- position: absolute;
298
- top: 0;
299
- left: 0;
300
- right: 0;
301
- height: 6px;
302
- background: linear-gradient(135deg, #667eea, #764ba2, #6B73FF);
303
  }
304
-
305
- /* Input Section Styling */
306
  .input-container {
307
  max-width: 800px;
308
  margin: 0 auto;
309
  }
310
-
311
  .stTextArea > div > div > textarea {
312
- border-radius: 16px !important;
313
- border: 2px solid #e2e8f0 !important;
314
- padding: 1.5rem !important;
315
- font-size: 1.1rem !important;
316
  font-family: 'Inter', sans-serif !important;
317
- transition: all 0.3s ease !important;
318
- background: #fafafa !important;
319
- resize: vertical !important;
320
- min-height: 200px !important;
321
  }
322
-
323
  .stTextArea > div > div > textarea:focus {
324
  border-color: #667eea !important;
325
- box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1) !important;
326
- background: white !important;
327
  outline: none !important;
328
  }
329
-
330
- .stTextArea > div > div > textarea::placeholder {
331
- color: #a0aec0 !important;
332
- font-style: italic !important;
333
- }
334
-
335
- /* Enhanced Button Styling */
336
  .stButton > button {
337
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
338
  color: white !important;
339
- border: none !important;
340
- border-radius: 16px !important;
341
- padding: 1rem 3rem !important;
342
- font-size: 1.2rem !important;
343
- font-weight: 600 !important;
344
- font-family: 'Poppins', sans-serif !important;
345
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
346
- box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4) !important;
347
  width: 100% !important;
348
- position: relative !important;
349
- overflow: hidden !important;
350
  }
351
-
352
  .stButton > button:hover {
353
- transform: translateY(-3px) !important;
354
- box-shadow: 0 15px 35px rgba(102, 126, 234, 0.6) !important;
355
- background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%) !important;
356
- }
357
-
358
- .stButton > button:active {
359
- transform: translateY(-1px) !important;
360
  }
361
-
362
  /* Results Section */
363
  .results-container {
364
- margin-top: 3rem;
365
- padding: 2rem;
366
- background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%);
367
- border-radius: 20px;
368
- border: 1px solid #e2e8f0;
369
  }
370
-
371
  .result-card {
372
- background: white;
373
- padding: 2.5rem;
374
- border-radius: 20px;
375
- margin: 1.5rem 0;
376
- box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
377
- border-left: 6px solid transparent;
378
- transition: all 0.3s ease;
379
- }
380
-
381
- .result-card:hover {
382
- transform: translateY(-2px);
383
- box-shadow: 0 12px 35px rgba(0, 0, 0, 0.12);
384
  }
385
-
386
- .prediction-badge {
387
- display: inline-flex;
388
- align-items: center;
389
- gap: 0.75rem;
390
- padding: 1rem 2rem;
391
- border-radius: 50px;
392
- font-weight: 700;
393
- font-size: 1.1rem;
394
- margin-bottom: 1rem;
395
- }
396
-
397
  .fake-news {
398
- background: linear-gradient(135deg, #fed7d7 0%, #feb2b2 100%);
399
- color: #c53030;
400
- border-left-color: #e53e3e;
401
  }
402
-
403
  .real-news {
404
- background: linear-gradient(135deg, #c6f6d5 0%, #9ae6b4 100%);
405
- color: #2f855a;
406
  border-left-color: #38a169;
407
  }
408
-
409
- .confidence-score {
410
- font-size: 1.4rem;
411
- font-weight: 700;
412
- margin-left: auto;
413
- }
414
-
415
- /* Analysis Cards */
416
- .analysis-grid {
417
- display: grid;
418
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
419
- gap: 2rem;
420
- margin: 2rem 0;
421
- }
422
-
423
- .analysis-card {
424
- background: white;
425
- padding: 2rem;
426
- border-radius: 16px;
427
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
428
- border-top: 4px solid #667eea;
429
- }
430
-
431
- .analysis-title {
432
- font-family: 'Poppins', sans-serif;
433
- font-size: 1.3rem;
434
  font-weight: 600;
435
- color: #1a202c;
436
  margin-bottom: 1rem;
437
- display: flex;
438
- align-items: center;
439
- gap: 0.5rem;
440
- }
441
-
442
- .analysis-content {
443
- color: #4a5568;
444
- line-height: 1.6;
445
  }
446
-
447
- .analysis-list {
448
- list-style: none;
449
- padding: 0;
450
- }
451
-
452
- .analysis-list li {
453
- padding: 0.5rem 0;
454
- padding-left: 1.5rem;
455
- position: relative;
456
- border-bottom: 1px solid #f1f5f9;
457
- }
458
-
459
- .analysis-list li:before {
460
- content: '✓';
461
- position: absolute;
462
- left: 0;
463
- color: #667eea;
464
- font-weight: bold;
465
- }
466
-
467
- .analysis-list li:last-child {
468
- border-bottom: none;
469
  }
470
-
471
  /* Chart Containers */
472
  .chart-container {
473
- background: white;
474
- padding: 2rem;
475
- border-radius: 16px;
 
476
  margin: 1rem 0;
477
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
478
- border: 1px solid #f1f5f9;
479
  }
480
-
481
  /* Footer */
482
  .footer {
483
- background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%);
484
- color: white;
485
- padding: 4rem 2rem 2rem;
486
  text-align: center;
487
- margin-top: 5rem;
488
- position: relative;
489
- overflow: hidden;
490
- }
491
-
492
- .footer::before {
493
- content: '';
494
- position: absolute;
495
- top: 0;
496
- left: 0;
497
- right: 0;
498
- height: 6px;
499
- background: linear-gradient(135deg, #667eea, #764ba2, #6B73FF);
500
- }
501
-
502
- .footer-content {
503
- max-width: 1200px;
504
- margin: 0 auto;
505
- position: relative;
506
- z-index: 2;
507
- }
508
-
509
- .footer-title {
510
- font-family: 'Poppins', sans-serif;
511
- font-size: 2rem;
512
- font-weight: 700;
513
- margin-bottom: 1rem;
514
- background: linear-gradient(135deg, #667eea, #764ba2);
515
- -webkit-background-clip: text;
516
- -webkit-text-fill-color: transparent;
517
- background-clip: text;
518
- }
519
-
520
- .footer-text {
521
- color: #cbd5e0;
522
- margin-bottom: 2rem;
523
- line-height: 1.7;
524
- font-size: 1.1rem;
525
- }
526
-
527
- .footer-links {
528
- display: flex;
529
- justify-content: center;
530
- gap: 3rem;
531
- margin-bottom: 3rem;
532
- flex-wrap: wrap;
533
- }
534
-
535
- .footer-link {
536
- color: #cbd5e0;
537
- text-decoration: none;
538
- transition: all 0.3s ease;
539
- font-weight: 500;
540
- padding: 0.5rem 1rem;
541
- border-radius: 8px;
542
- }
543
-
544
- .footer-link:hover {
545
- color: white;
546
- background: rgba(102, 126, 234, 0.2);
547
- transform: translateY(-2px);
548
- }
549
-
550
- .footer-bottom {
551
- border-top: 1px solid #4a5568;
552
- padding-top: 2rem;
553
- color: #a0aec0;
554
- font-size: 0.95rem;
555
- line-height: 1.6;
556
- }
557
-
558
- /* Loading Spinner Custom */
559
- .stSpinner > div {
560
- border-color: #667eea transparent #667eea transparent !important;
561
- }
562
-
563
- /* Responsive Design */
564
- @media (max-width: 768px) {
565
- .hero-title {
566
- font-size: 3rem;
567
- }
568
-
569
- .hero-stats {
570
- flex-direction: column;
571
- gap: 1.5rem;
572
- }
573
-
574
- .features-grid {
575
- grid-template-columns: 1fr;
576
- }
577
-
578
- .main-content {
579
- margin: 2rem 1rem;
580
- padding: 2rem;
581
- }
582
-
583
- .section-title {
584
- font-size: 2.2rem;
585
- }
586
-
587
- .footer-links {
588
- flex-direction: column;
589
- gap: 1rem;
590
- }
591
-
592
- .analysis-grid {
593
- grid-template-columns: 1fr;
594
- }
595
- }
596
-
597
- @media (max-width: 480px) {
598
- .hero-title {
599
- font-size: 2.5rem;
600
- }
601
-
602
- .section-title {
603
- font-size: 2rem;
604
- }
605
-
606
- .feature-card {
607
- padding: 2rem 1.5rem;
608
- }
609
  }
610
  </style>
611
  """, unsafe_allow_html=True)
@@ -667,466 +296,155 @@ def predict_news(text):
667
  }
668
 
669
  def plot_confidence(probabilities):
670
- """Plot prediction confidence with enhanced styling."""
671
- colors = ['#22c55e', '#ef4444']
672
-
673
  fig = go.Figure(data=[
674
  go.Bar(
675
  x=list(probabilities.keys()),
676
  y=list(probabilities.values()),
677
  text=[f'{p:.1%}' for p in probabilities.values()],
678
  textposition='auto',
679
- textfont=dict(size=16, family="Poppins", color="white"),
680
  marker=dict(
681
- color=colors,
682
- line=dict(color='rgba(255,255,255,0.3)', width=2),
683
- pattern_shape="",
684
  ),
685
- hovertemplate='<b>%{x}</b><br>Confidence: %{y:.1%}<extra></extra>',
686
- width=[0.6, 0.6]
687
  )
688
  ])
689
-
690
  fig.update_layout(
691
- title={
692
- 'text': '📊 Prediction Confidence',
693
- 'x': 0.5,
694
- 'xanchor': 'center',
695
- 'font': {'size': 24, 'family': 'Poppins', 'color': '#1a202c'}
696
- },
697
- xaxis=dict(
698
- title='Classification',
699
- titlefont=dict(size=16, family='Inter', color='#4a5568'),
700
- tickfont=dict(size=14, family='Inter', color='#4a5568'),
701
- showgrid=False,
702
- ),
703
- yaxis=dict(
704
- title='Probability',
705
- titlefont=dict(size=16, family='Inter', color='#4a5568'),
706
- tickfont=dict(size=14, family='Inter', color='#4a5568'),
707
- range=[0, 1],
708
- tickformat='.0%',
709
- showgrid=True,
710
- gridcolor='rgba(0,0,0,0.05)',
711
- ),
712
  template='plotly_white',
713
- plot_bgcolor='rgba(0,0,0,0)',
714
- paper_bgcolor='rgba(0,0,0,0)',
715
- font={'family': 'Inter'},
716
- margin=dict(l=50, r=50, t=80, b=50),
717
- height=400
718
  )
719
  return fig
720
 
721
  def plot_attention(text, attention_weights):
722
- """Plot attention weights with enhanced styling."""
723
- tokens = text.split()[:20] # Limit to first 20 tokens for better visualization
724
  attention_weights = attention_weights[:len(tokens)]
725
-
726
  if isinstance(attention_weights, (list, np.ndarray)):
727
  attention_weights = np.array(attention_weights).flatten()
728
-
729
- # Normalize attention weights
730
- if len(attention_weights) > 0 and max(attention_weights) > 0:
731
- normalized_weights = attention_weights / max(attention_weights)
732
- else:
733
- normalized_weights = attention_weights
734
-
735
- # Create gradient colors
736
  colors = [f'rgba(102, 126, 234, {0.3 + 0.7 * float(w)})' for w in normalized_weights]
737
-
738
  fig = go.Figure(data=[
739
  go.Bar(
740
  x=tokens,
741
  y=attention_weights,
742
  text=[f'{float(w):.3f}' for w in attention_weights],
743
  textposition='auto',
744
- textfont=dict(size=12, family="Inter", color="white"),
745
- marker=dict(
746
- color=colors,
747
- line=dict(color='rgba(102, 126, 234, 0.8)', width=1),
748
- ),
749
- hovertemplate='<b>%{x}</b><br>Attention: %{y:.3f}<extra></extra>',
750
  )
751
  ])
752
-
753
  fig.update_layout(
754
- title={
755
- 'text': '🎯 Attention Weights Analysis',
756
- 'x': 0.5,
757
- 'xanchor': 'center',
758
- 'font': {'size': 24, 'family': 'Poppins', 'color': '#1a202c'}
759
- },
760
- xaxis=dict(
761
- title='Words/Tokens',
762
- titlefont=dict(size=16, family='Inter', color='#4a5568'),
763
- tickfont=dict(size=12, family='Inter', color='#4a5568'),
764
- tickangle=45,
765
- showgrid=False,
766
- ),
767
- yaxis=dict(
768
- title='Attention Score',
769
- titlefont=dict(size=16, family='Inter', color='#4a5568'),
770
- tickfont=dict(size=14, family='Inter', color='#4a5568'),
771
- showgrid=True,
772
- gridcolor='rgba(0,0,0,0.05)',
773
- ),
774
  template='plotly_white',
775
- plot_bgcolor='rgba(0,0,0,0)',
776
- paper_bgcolor='rgba(0,0,0,0)',
777
- font={'family': 'Inter'},
778
- margin=dict(l=50, r=50, t=80, b=100),
779
- height=450
780
  )
781
  return fig
782
 
783
  def main():
784
- # Header Navigation
785
  st.markdown("""
786
- <div class="header-nav">
787
- <div class="nav-brand">
788
- 🛡️ TruthCheck
789
  </div>
790
  </div>
791
  """, unsafe_allow_html=True)
792
 
793
  # Hero Section
794
  st.markdown("""
795
- <div class="hero-container">
796
- <div class="hero-content">
797
- <div class="hero-badge">
798
- Powered by Advanced AI Technology
799
- </div>
800
- <h1 class="hero-title">🛡️ TruthCheck</h1>
801
- <h2 style="font-size: 1.8rem; font-weight: 600; margin-bottom: 1rem; opacity: 0.9;">Advanced Fake News Detector</h2>
802
- <p class="hero-subtitle">
803
- 🔍 Leverage cutting-edge deep learning technology to instantly analyze and verify news articles.
804
- Our hybrid BERT-BiLSTM model delivers precise, trustworthy results with detailed explanations.
805
- </p>
806
- <div class="hero-stats">
807
- <div class="stat-item">
808
- <span class="stat-number">95%+</span>
809
- <span class="stat-label">Accuracy</span>
810
- </div>
811
- <div class="stat-item">
812
- <span class="stat-number">&lt;3s</span>
813
- <span class="stat-label">Analysis Time</span>
814
- </div>
815
- <div class="stat-item">
816
- <span class="stat-number">24/7</span>
817
- <span class="stat-label">Available</span>
818
- </div>
819
- </div>
820
- </div>
821
- </div>
822
- """, unsafe_allow_html=True)
823
-
824
- # Features Section
825
- st.markdown("""
826
- <div class="features-section">
827
- <div class="section-header">
828
- <div class="section-badge">
829
- 🚀 Advanced Features
830
- </div>
831
- <h2 class="section-title">Why Choose TruthCheck?</h2>
832
- <p class="section-description">
833
- Our state-of-the-art AI combines multiple advanced technologies to deliver unparalleled accuracy in fake news detection
834
- </p>
835
- </div>
836
- <div class="features-grid">
837
- <div class="feature-card">
838
- <span class="feature-icon">🤖</span>
839
- <h3 class="feature-title">BERT Transformer</h3>
840
- <p class="feature-description">
841
- Utilizes state-of-the-art BERT transformer architecture for deep contextual understanding and semantic analysis of news content with unprecedented accuracy.
842
  </p>
843
  </div>
844
- <div class="feature-card">
845
- <span class="feature-icon">🧠</span>
846
- <h3 class="feature-title">BiLSTM Networks</h3>
847
- <p class="feature-description">
848
- Advanced bidirectional LSTM networks capture sequential patterns, temporal dependencies, and linguistic structures in news articles for comprehensive analysis.
849
- </p>
850
- </div>
851
- <div class="feature-card">
852
- <span class="feature-icon">👁️</span>
853
- <h3 class="feature-title">Attention Mechanism</h3>
854
- <p class="feature-description">
855
- Sophisticated attention layers provide transparent insights into model decision-making, highlighting key phrases and suspicious content patterns.
856
- </p>
857
- </div>
858
- <div class="feature-card">
859
- <span class="feature-icon">⚡</span>
860
- <h3 class="feature-title">Real-time Processing</h3>
861
- <p class="feature-description">
862
- Lightning-fast analysis delivers results in seconds, enabling immediate verification of news content without compromising accuracy or detail.
863
- </p>
864
- </div>
865
- <div class="feature-card">
866
- <span class="feature-icon">📊</span>
867
- <h3 class="feature-title">Confidence Scoring</h3>
868
- <p class="feature-description">
869
- Detailed confidence metrics and probability distributions provide clear insights into prediction reliability and uncertainty levels.
870
- </p>
871
- </div>
872
- <div class="feature-card">
873
- <span class="feature-icon">🔒</span>
874
- <h3 class="feature-title">Privacy Protected</h3>
875
- <p class="feature-description">
876
- Your data is processed securely with no storage or tracking. Complete privacy protection ensures your news analysis remains confidential.
877
- </p>
878
  </div>
879
  </div>
880
  </div>
881
  """, unsafe_allow_html=True)
882
 
883
- # Main Content Section
884
  st.markdown("""
885
- <div class="main-content">
886
- <div class="section-header">
887
- <div class="section-badge">
888
- 🔍 AI Analysis
889
- </div>
890
- <h2 class="section-title">Analyze News Article</h2>
891
- <p class="section-description">
892
- 📝 Simply paste any news article below and our advanced AI will provide instant, detailed analysis with confidence scores, attention weights, and comprehensive insights.
893
  </p>
894
  </div>
895
- <div class="input-container">
896
  """, unsafe_allow_html=True)
897
 
898
  # Input Section
 
899
  news_text = st.text_area(
900
- "",
901
- height=250,
902
- placeholder="📰 Paste your news article here for comprehensive AI analysis...\n\n💡 Tip: Longer articles (100+ words) typically provide more accurate results.\n\n🚀 Our AI will analyze linguistic patterns, factual consistency, and content structure to determine authenticity.",
903
- key="news_input",
904
- help="Enter the full text of a news article for analysis. The more complete the article, the more accurate the analysis will be."
905
  )
906
-
907
- st.markdown("</div>", unsafe_allow_html=True)
908
-
909
- # Enhanced Button Section
910
  col1, col2, col3 = st.columns([1, 2, 1])
911
  with col2:
912
- analyze_button = st.button(
913
- "🔍 Analyze Article with AI",
914
- key="analyze_button",
915
- help="Click to start AI-powered analysis of the news article"
916
- )
917
 
918
  if analyze_button:
919
  if news_text and len(news_text.strip()) > 10:
920
- with st.spinner("🤖 AI is analyzing the article... Please wait"):
921
  try:
922
  result = predict_news(news_text)
 
923
 
924
- # Results Container
925
- st.markdown('<div class="results-container">', unsafe_allow_html=True)
926
-
927
- # Main Prediction Result
928
- col1, col2 = st.columns([1, 1], gap="large")
929
-
930
  with col1:
931
- st.markdown("### 🎯 AI Prediction Result")
932
  if result['label'] == 'FAKE':
933
  st.markdown(f'''
934
  <div class="result-card fake-news">
935
- <div class="prediction-badge">
936
- 🚨 FAKE NEWS DETECTED
937
- <span class="confidence-score">{result["confidence"]:.1%}</span>
938
- </div>
939
- <div style="font-size: 1.1rem; color: #c53030; line-height: 1.6;">
940
- <strong>⚠️ Warning:</strong> Our AI model has identified this content as likely misinformation based on linguistic patterns, structural analysis, and content inconsistencies.
941
- </div>
942
  </div>
943
  ''', unsafe_allow_html=True)
944
  else:
945
  st.markdown(f'''
946
  <div class="result-card real-news">
947
- <div class="prediction-badge">
948
- AUTHENTIC NEWS
949
- <span class="confidence-score">{result["confidence"]:.1%}</span>
950
- </div>
951
- <div style="font-size: 1.1rem; color: #2f855a; line-height: 1.6;">
952
- <strong>✓ Verified:</strong> This content appears to be legitimate news based on professional writing style, factual consistency, and structural integrity.
953
- </div>
954
  </div>
955
  ''', unsafe_allow_html=True)
956
 
957
  with col2:
958
- st.markdown("### 📈 Confidence Breakdown")
959
  st.markdown('<div class="chart-container">', unsafe_allow_html=True)
960
  st.plotly_chart(plot_confidence(result['probabilities']), use_container_width=True)
961
  st.markdown('</div>', unsafe_allow_html=True)
962
 
963
  # Attention Analysis
964
- st.markdown("### 🎯 AI Attention Analysis")
965
- st.markdown("""
966
- <p style="color: #4a5568; text-align: center; margin-bottom: 2rem; font-size: 1.1rem; line-height: 1.6;">
967
- 🧠 The visualization below reveals which words and phrases our AI model focused on during analysis.
968
- <strong>Higher attention scores</strong> (darker colors) indicate words that significantly influenced the prediction.
969
- </p>
970
- """, unsafe_allow_html=True)
971
  st.markdown('<div class="chart-container">', unsafe_allow_html=True)
972
  st.plotly_chart(plot_attention(news_text, result['attention_weights']), use_container_width=True)
973
- st.markdown('</div>', unsafe_allow_html=True)
974
-
975
- # Detailed Analysis
976
- st.markdown("### 🔍 Comprehensive AI Analysis")
977
-
978
- if result['label'] == 'FAKE':
979
- st.markdown("""
980
- <div class="analysis-grid">
981
- <div class="analysis-card">
982
- <h4 class="analysis-title">⚠️ Misinformation Indicators</h4>
983
- <div class="analysis-content">
984
- <ul class="analysis-list">
985
- <li><strong>Linguistic Anomalies:</strong> Detected language patterns commonly associated with fabricated content and misinformation campaigns</li>
986
- <li><strong>Structural Inconsistencies:</strong> Identified irregular text flow, unusual formatting, or non-standard journalistic structure</li>
987
- <li><strong>Content Reliability:</strong> Found potential factual inconsistencies, exaggerated claims, or misleading statements</li>
988
- <li><strong>Emotional Manipulation:</strong> High attention on emotionally charged language designed to provoke strong reactions</li>
989
- <li><strong>Source Credibility:</strong> Writing style and presentation lack hallmarks of professional journalism</li>
990
- </ul>
991
- </div>
992
- </div>
993
- <div class="analysis-card">
994
- <h4 class="analysis-title">🛡️ Recommended Actions</h4>
995
- <div class="analysis-content">
996
- <ul class="analysis-list">
997
- <li><strong>Verify Sources:</strong> Cross-reference information with multiple reputable news outlets and official sources</li>
998
- <li><strong>Check Facts:</strong> Use fact-checking websites like Snopes, PolitiFact, or FactCheck.org for verification</li>
999
- <li><strong>Avoid Sharing:</strong> Do not share this content until authenticity is confirmed through reliable sources</li>
1000
- <li><strong>Report Misinformation:</strong> Consider reporting to platform moderators if shared on social media</li>
1001
- <li><strong>Stay Informed:</strong> Follow trusted news sources for accurate information on this topic</li>
1002
- </ul>
1003
- </div>
1004
- </div>
1005
- </div>
1006
- """, unsafe_allow_html=True)
1007
- else:
1008
- st.markdown("""
1009
- <div class="analysis-grid">
1010
- <div class="analysis-card">
1011
- <h4 class="analysis-title">✅ Authenticity Indicators</h4>
1012
- <div class="analysis-content">
1013
- <ul class="analysis-list">
1014
- <li><strong>Professional Language:</strong> Demonstrates standard journalistic writing style with balanced, objective reporting tone</li>
1015
- <li><strong>Structural Integrity:</strong> Follows conventional news article format with proper introduction, body, and conclusion</li>
1016
- <li><strong>Factual Consistency:</strong> Information appears coherent, logically structured, and factually consistent throughout</li>
1017
- <li><strong>Neutral Presentation:</strong> Maintains objectivity without excessive emotional language or bias indicators</li>
1018
- <li><strong>Credible Content:</strong> Contains specific details, proper context, and verifiable information patterns</li>
1019
- </ul>
1020
- </div>
1021
- </div>
1022
- <div class="analysis-card">
1023
- <h4 class="analysis-title">📋 Best Practices</h4>
1024
- <div class="analysis-content">
1025
- <ul class="analysis-list">
1026
- <li><strong>Continue Verification:</strong> While likely authentic, always cross-reference important news from multiple sources</li>
1027
- <li><strong>Check Publication Date:</strong> Ensure the information is current and hasn't been superseded by newer developments</li>
1028
- <li><strong>Verify Author Credentials:</strong> Research the author's background and expertise in the subject matter</li>
1029
- <li><strong>Review Source Reputation:</strong> Confirm the publication's credibility and editorial standards</li>
1030
- <li><strong>Stay Updated:</strong> Monitor for any corrections, updates, or follow-up reporting on the topic</li>
1031
- </ul>
1032
- </div>
1033
- </div>
1034
- </div>
1035
- """, unsafe_allow_html=True)
1036
-
1037
- # Technical Details
1038
- with st.expander("🔧 Technical Analysis Details", expanded=False):
1039
- col1, col2, col3 = st.columns(3)
1040
-
1041
- with col1:
1042
- st.metric(
1043
- label="🎯 Prediction Confidence",
1044
- value=f"{result['confidence']:.2%}",
1045
- help="Overall confidence in the AI's prediction"
1046
- )
1047
-
1048
- with col2:
1049
- st.metric(
1050
- label="📊 REAL Probability",
1051
- value=f"{result['probabilities']['REAL']:.2%}",
1052
- help="Probability that the content is authentic news"
1053
- )
1054
-
1055
- with col3:
1056
- st.metric(
1057
- label="⚠️ FAKE Probability",
1058
- value=f"{result['probabilities']['FAKE']:.2%}",
1059
- help="Probability that the content is fake news"
1060
- )
1061
-
1062
- st.markdown("---")
1063
- st.markdown("""
1064
- **🤖 Model Information:**
1065
- - **Architecture:** Hybrid BERT + BiLSTM with Attention Mechanism
1066
- - **Training Data:** Extensive dataset of verified real and fake news articles
1067
- - **Features:** Contextual embeddings, sequential patterns, attention weights
1068
- - **Performance:** 95%+ accuracy on validation datasets
1069
- """)
1070
-
1071
- st.markdown('</div>', unsafe_allow_html=True)
1072
-
1073
  except Exception as e:
1074
- st.error(f"""
1075
- 🚨 **Analysis Error Occurred**
1076
-
1077
- We encountered an issue while analyzing your article. This might be due to:
1078
- - Technical server issues
1079
- - Content formatting problems
1080
- - Model loading difficulties
1081
-
1082
- **Error Details:** {str(e)}
1083
-
1084
- Please try again in a few moments or contact support if the issue persists.
1085
- """)
1086
  else:
1087
- st.markdown('''
1088
- <div class="main-content">
1089
- <div style="background: linear-gradient(135deg, #fef2f2 0%, #fecaca 100%); color: #991b1b; padding: 2rem; border-radius: 16px; text-align: center; border-left: 6px solid #ef4444;">
1090
- <h3 style="margin-bottom: 1rem;">⚠️ Input Required</h3>
1091
- <p style="font-size: 1.1rem; line-height: 1.6;">
1092
- Please enter a news article (at least 10 words) to perform AI analysis.
1093
- <br><strong>💡 Tip:</strong> Longer, complete articles provide more accurate results.
1094
- </p>
1095
- </div>
1096
- </div>
1097
- ''', unsafe_allow_html=True)
1098
-
1099
- st.markdown('</div>', unsafe_allow_html=True)
1100
 
1101
  # Footer
1102
  st.markdown("""
1103
  <div class="footer">
1104
- <div class="footer-content">
1105
- <h3 class="footer-title">🛡️ TruthCheck AI</h3>
1106
- <p class="footer-text">
1107
- 🌟 Empowering global communities with cutting-edge AI-driven news verification technology.
1108
- Built with advanced deep learning models, natural language processing, and transparent machine learning practices
1109
- to combat misinformation and promote media literacy worldwide.
1110
- </p>
1111
- <div class="footer-links">
1112
- <a href="#" class="footer-link">📖 About TruthCheck</a>
1113
- <a href="#" class="footer-link">🔬 How It Works</a>
1114
- <a href="#" class="footer-link">📊 Accuracy Reports</a>
1115
- <a href="#" class="footer-link">🔒 Privacy Policy</a>
1116
- <a href="#" class="footer-link">📞 Contact Support</a>
1117
- <a href="#" class="footer-link">🆘 Report Issues</a>
1118
- </div>
1119
- <div class="footer-bottom">
1120
- <p style="margin-bottom: 1rem;">
1121
- &copy; 2025 TruthCheck AI. Built with ❤️ using Streamlit, BERT, PyTorch, and Advanced Machine Learning.
1122
- </p>
1123
- <p>
1124
- <strong>🔍 Disclaimer:</strong> This tool provides AI-based analysis for informational purposes.
1125
- Always verify important information through multiple reliable sources and exercise critical thinking.
1126
- Our AI model achieves high accuracy but is not infallible - human judgment remains essential.
1127
- </p>
1128
- </div>
1129
- </div>
1130
  </div>
1131
  """, unsafe_allow_html=True)
1132
 
 
35
  from src.config.config import *
36
  from src.data.preprocessor import TextPreprocessor
37
 
38
+ # Custom CSS for clean, modern styling
39
  st.markdown("""
40
  <style>
41
  /* Import Google Fonts */
42
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
43
+
44
  /* Global Styles */
45
  * {
46
  margin: 0;
47
  padding: 0;
48
  box-sizing: border-box;
49
  }
50
+
 
 
 
 
 
51
  .stApp {
52
+ font-family: 'Inter', sans-serif;
53
+ background: #f8fafc;
54
  min-height: 100vh;
55
  color: #2d3748;
56
  }
57
+
58
  /* Hide Streamlit elements */
59
  #MainMenu {visibility: hidden;}
60
  footer {visibility: hidden;}
61
  .stDeployButton {display: none;}
62
  header {visibility: hidden;}
63
  .stApp > header {visibility: hidden;}
64
+
65
+ /* Container */
66
+ .container {
67
+ max-width: 1200px;
68
+ margin: 0 auto;
69
+ padding: 2rem;
70
+ }
71
+
72
+ /* Header */
73
+ .header {
74
+ background: #ffffff;
75
+ padding: 1.5rem 2rem;
76
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
77
  position: sticky;
78
  top: 0;
79
  z-index: 1000;
 
80
  }
81
+
82
+ .header-title {
 
83
  font-size: 1.8rem;
84
+ font-weight: 700;
85
+ color: #1a202c;
 
 
 
 
 
 
86
  }
87
+
88
  /* Hero Section */
89
+ .hero {
90
+ display: flex;
91
+ gap: 2rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  margin-bottom: 3rem;
 
 
 
 
 
93
  }
94
+
95
+ .hero-left {
96
+ flex: 1;
97
+ padding: 2rem;
98
+ }
99
+
100
+ .hero-right {
101
+ flex: 1;
102
  display: flex;
103
+ align-items: center;
104
  justify-content: center;
 
 
105
  }
106
+
107
+ .hero-right img {
108
+ max-width: 100%;
109
+ height: auto;
110
+ border-radius: 12px;
111
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
112
  }
113
+
114
+ .hero-title {
115
  font-size: 2.5rem;
116
  font-weight: 700;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  color: #1a202c;
118
  margin-bottom: 1rem;
 
119
  }
120
+
121
+ .hero-text {
122
+ font-size: 1.1rem;
123
  color: #4a5568;
 
 
124
  line-height: 1.6;
125
  }
126
+
127
+ /* About Section */
128
+ .about-section {
129
+ margin-bottom: 3rem;
 
 
 
 
 
 
 
 
 
130
  text-align: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
132
+
133
+ .about-title {
134
+ font-size: 2rem;
 
135
  font-weight: 600;
136
  color: #1a202c;
137
  margin-bottom: 1rem;
138
  }
139
+
140
+ .about-text {
141
+ font-size: 1rem;
142
  color: #4a5568;
143
  line-height: 1.6;
144
+ max-width: 800px;
145
+ margin: 0 auto;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  }
147
+
148
+ /* Input Section */
149
  .input-container {
150
  max-width: 800px;
151
  margin: 0 auto;
152
  }
153
+
154
  .stTextArea > div > div > textarea {
155
+ border-radius: 12px !important;
156
+ border: 1px solid #e2e8f0 !important;
157
+ padding: 1rem !important;
158
+ font-size: 1rem !important;
159
  font-family: 'Inter', sans-serif !important;
160
+ background: #ffffff !important;
161
+ min-height: 150px !important;
 
 
162
  }
163
+
164
  .stTextArea > div > div > textarea:focus {
165
  border-color: #667eea !important;
166
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
 
167
  outline: none !important;
168
  }
169
+
 
 
 
 
 
 
170
  .stButton > button {
171
+ background: #667eea !important;
172
  color: white !important;
173
+ border-radius: 8px !important;
174
+ padding: 0.75rem 2rem !important;
175
+ font-size: 1rem !important;
176
+ font-weight: 500 !important;
177
+ font-family: 'Inter', sans-serif !important;
178
+ transition: all 0.3s ease !important;
 
 
179
  width: 100% !important;
 
 
180
  }
181
+
182
  .stButton > button:hover {
183
+ background: #5a6fd8 !important;
184
+ transform: translateY(-2px) !important;
 
 
 
 
 
185
  }
186
+
187
  /* Results Section */
188
  .results-container {
189
+ margin-top: 2rem;
190
+ padding: 1.5rem;
191
+ background: #ffffff;
192
+ border-radius: 12px;
193
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
194
  }
195
+
196
  .result-card {
197
+ padding: 1.5rem;
198
+ border-radius: 12px;
199
+ border-left: 4px solid transparent;
 
 
 
 
 
 
 
 
 
200
  }
201
+
 
 
 
 
 
 
 
 
 
 
 
202
  .fake-news {
203
+ background: #fef2f2;
204
+ border-left-color: #ef4444;
 
205
  }
206
+
207
  .real-news {
208
+ background: #f0fff4;
 
209
  border-left-color: #38a169;
210
  }
211
+
212
+ .prediction-badge {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  font-weight: 600;
214
+ font-size: 1rem;
215
  margin-bottom: 1rem;
 
 
 
 
 
 
 
 
216
  }
217
+
218
+ .confidence-score {
219
+ font-weight: 600;
220
+ margin-left: auto;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  }
222
+
223
  /* Chart Containers */
224
  .chart-container {
225
+ padding: 1.5rem;
226
+ border-radius: 12px;
227
+ background: #ffffff;
228
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
229
  margin: 1rem 0;
 
 
230
  }
231
+
232
  /* Footer */
233
  .footer {
234
+ margin-top: 3rem;
235
+ padding: 1rem;
 
236
  text-align: center;
237
+ border-top: 1px solid #e2e8f0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  }
239
  </style>
240
  """, unsafe_allow_html=True)
 
296
  }
297
 
298
  def plot_confidence(probabilities):
299
+ """Plot prediction confidence with simplified styling."""
 
 
300
  fig = go.Figure(data=[
301
  go.Bar(
302
  x=list(probabilities.keys()),
303
  y=list(probabilities.values()),
304
  text=[f'{p:.1%}' for p in probabilities.values()],
305
  textposition='auto',
 
306
  marker=dict(
307
+ color=['#38a169', '#ef4444'],
308
+ line=dict(color='#ffffff', width=1),
 
309
  ),
 
 
310
  )
311
  ])
 
312
  fig.update_layout(
313
+ title={'text': 'Prediction Confidence', 'x': 0.5, 'xanchor': 'center'},
314
+ xaxis=dict(title='Classification'),
315
+ yaxis=dict(title='Probability', range=[0, 1], tickformat='.0%'),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  template='plotly_white',
317
+ height=300
 
 
 
 
318
  )
319
  return fig
320
 
321
  def plot_attention(text, attention_weights):
322
+ """Plot attention weights with simplified styling."""
323
+ tokens = text.split()[:20]
324
  attention_weights = attention_weights[:len(tokens)]
 
325
  if isinstance(attention_weights, (list, np.ndarray)):
326
  attention_weights = np.array(attention_weights).flatten()
327
+ normalized_weights = attention_weights / max(attention_weights) if max(attention_weights) > 0 else attention_weights
 
 
 
 
 
 
 
328
  colors = [f'rgba(102, 126, 234, {0.3 + 0.7 * float(w)})' for w in normalized_weights]
 
329
  fig = go.Figure(data=[
330
  go.Bar(
331
  x=tokens,
332
  y=attention_weights,
333
  text=[f'{float(w):.3f}' for w in attention_weights],
334
  textposition='auto',
335
+ marker=dict(color=colors),
 
 
 
 
 
336
  )
337
  ])
 
338
  fig.update_layout(
339
+ title={'text': 'Attention Weights', 'x': 0.5, 'xanchor': 'center'},
340
+ xaxis=dict(title='Words', tickangle=45),
341
+ yaxis=dict(title='Attention Score'),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  template='plotly_white',
343
+ height=400
 
 
 
 
344
  )
345
  return fig
346
 
347
  def main():
348
+ # Header
349
  st.markdown("""
350
+ <div class="header">
351
+ <div class="container">
352
+ <h1 class="header-title">TruthCheck</h1>
353
  </div>
354
  </div>
355
  """, unsafe_allow_html=True)
356
 
357
  # Hero Section
358
  st.markdown("""
359
+ <div class="container">
360
+ <div class="hero">
361
+ <div class="hero-left">
362
+ <h2 class="hero-title">Advanced Fake News Detection</h2>
363
+ <p class="hero-text">
364
+ Use our AI-powered tool to verify news articles instantly. Powered by BERT and BiLSTM, TruthCheck provides accurate, transparent analysis of news authenticity.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  </p>
366
  </div>
367
+ <div class="hero-right">
368
+ <img src="/hero.png" alt="TruthCheck Illustration">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
  </div>
370
  </div>
371
  </div>
372
  """, unsafe_allow_html=True)
373
 
374
+ # About Section
375
  st.markdown("""
376
+ <div class="container">
377
+ <div class="about-section">
378
+ <h2 class="about-title">About TruthCheck</h2>
379
+ <p class="about-text">
380
+ TruthCheck leverages a hybrid BERT-BiLSTM model to detect fake news with high accuracy. Simply paste a news article, and our AI will analyze its authenticity, providing confidence scores and attention insights.
 
 
 
381
  </p>
382
  </div>
383
+ </div>
384
  """, unsafe_allow_html=True)
385
 
386
  # Input Section
387
+ st.markdown('<div class="container"><div class="input-container">', unsafe_allow_html=True)
388
  news_text = st.text_area(
389
+ "Paste News Article",
390
+ height=150,
391
+ placeholder="Paste your news article here for AI analysis...",
392
+ key="news_input"
 
393
  )
394
+ st.markdown('</div>', unsafe_allow_html=True)
395
+
396
+ # Analyze Button
397
+ st.markdown('<div class="container">', unsafe_allow_html=True)
398
  col1, col2, col3 = st.columns([1, 2, 1])
399
  with col2:
400
+ analyze_button = st.button("Analyze Article", key="analyze_button")
401
+ st.markdown('</div>', unsafe_allow_html=True)
 
 
 
402
 
403
  if analyze_button:
404
  if news_text and len(news_text.strip()) > 10:
405
+ with st.spinner("Analyzing article..."):
406
  try:
407
  result = predict_news(news_text)
408
+ st.markdown('<div class="container"><div class="results-container">', unsafe_allow_html=True)
409
 
410
+ # Prediction Result
411
+ col1, col2 = st.columns([1, 1])
 
 
 
 
412
  with col1:
 
413
  if result['label'] == 'FAKE':
414
  st.markdown(f'''
415
  <div class="result-card fake-news">
416
+ <div class="prediction-badge">FAKE NEWS DETECTED <span class="confidence-score">{result["confidence"]:.1%}</span></div>
417
+ <p>Our AI model has identified this content as likely misinformation based on linguistic patterns and content analysis.</p>
 
 
 
 
 
418
  </div>
419
  ''', unsafe_allow_html=True)
420
  else:
421
  st.markdown(f'''
422
  <div class="result-card real-news">
423
+ <div class="prediction-badge">AUTHENTIC NEWS <span class="confidence-score">{result["confidence"]:.1%}</span></div>
424
+ <p>This content appears to be legitimate news based on professional writing style and factual consistency.</p>
 
 
 
 
 
425
  </div>
426
  ''', unsafe_allow_html=True)
427
 
428
  with col2:
 
429
  st.markdown('<div class="chart-container">', unsafe_allow_html=True)
430
  st.plotly_chart(plot_confidence(result['probabilities']), use_container_width=True)
431
  st.markdown('</div>', unsafe_allow_html=True)
432
 
433
  # Attention Analysis
 
 
 
 
 
 
 
434
  st.markdown('<div class="chart-container">', unsafe_allow_html=True)
435
  st.plotly_chart(plot_attention(news_text, result['attention_weights']), use_container_width=True)
436
+ st.markdown('</div></div></div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
  except Exception as e:
438
+ st.error(f"Error: {str(e)}. Please try again or contact support.")
 
 
 
 
 
 
 
 
 
 
 
439
  else:
440
+ st.markdown('<div class="container">', unsafe_allow_html=True)
441
+ st.error("Please enter a news article (at least 10 words) for analysis.")
442
+ st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
443
 
444
  # Footer
445
  st.markdown("""
446
  <div class="footer">
447
+ <p style="text-align: center; font-weight: 600; font-size: 16px;">💻 Developed with ❤️ using Streamlit | © 2024</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  </div>
449
  """, unsafe_allow_html=True)
450