TruthCheck / src /app.py
KhaqanNasir's picture
Update src/app.py
0dd07a9 verified
raw
history blame
41.9 kB
import streamlit as st
import torch
import pandas as pd
import numpy as np
from pathlib import Path
import sys
import plotly.express as px
import plotly.graph_objects as go
from transformers import BertTokenizer
import nltk
# Download required NLTK data
try:
nltk.data.find('tokenizers/punkt')
except LookupError:
nltk.download('punkt')
try:
nltk.data.find('corpora/stopwords')
except LookupError:
nltk.download('stopwords')
try:
nltk.data.find('tokenizers/punkt_tab')
except LookupError:
nltk.download('punkt_tab')
try:
nltk.data.find('corpora/wordnet')
except LookupError:
nltk.download('wordnet')
# Add project root to Python path
project_root = Path(__file__).parent.parent
sys.path.append(str(project_root))
from src.models.hybrid_model import HybridFakeNewsDetector
from src.config.config import *
from src.data.preprocessor import TextPreprocessor
# Custom CSS for modern, enhanced styling
st.markdown("""
<style>
/* Import Google Fonts */
@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');
/* Global Styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.main {
padding: 0 !important;
max-width: 100% !important;
}
.stApp {
font-family: 'Inter', 'Poppins', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #6B73FF 100%);
min-height: 100vh;
color: #2d3748;
}
/* Hide Streamlit elements */
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}
.stDeployButton {display: none;}
header {visibility: hidden;}
.stApp > header {visibility: hidden;}
/* Header Navigation */
.header-nav {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
padding: 1rem 2rem;
position: sticky;
top: 0;
z-index: 1000;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
.nav-brand {
font-family: 'Poppins', sans-serif;
font-size: 1.8rem;
font-weight: 800;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
/* Hero Section */
.hero-container {
background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #6B73FF 100%);
padding: 6rem 2rem;
text-align: center;
color: white;
position: relative;
overflow: hidden;
}
.hero-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
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>');
pointer-events: none;
}
.hero-content {
position: relative;
z-index: 2;
max-width: 800px;
margin: 0 auto;
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: 0.5rem;
background: rgba(255, 255, 255, 0.2);
padding: 0.5rem 1.5rem;
border-radius: 50px;
font-size: 0.9rem;
font-weight: 500;
margin-bottom: 2rem;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.hero-title {
font-family: 'Poppins', sans-serif;
font-size: 4.5rem;
font-weight: 900;
margin-bottom: 1.5rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
background: linear-gradient(45deg, #fff, #e0e7ff, #fff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1.1;
}
.hero-subtitle {
font-size: 1.4rem;
font-weight: 400;
margin-bottom: 3rem;
opacity: 0.95;
line-height: 1.7;
max-width: 700px;
margin-left: auto;
margin-right: auto;
}
.hero-stats {
display: flex;
justify-content: center;
gap: 3rem;
margin-top: 2rem;
}
.stat-item {
text-align: center;
}
.stat-number {
font-size: 2.5rem;
font-weight: 700;
display: block;
}
.stat-label {
font-size: 0.9rem;
opacity: 0.8;
}
/* Features Section */
.features-section {
padding: 5rem 2rem;
background: #f8fafc;
position: relative;
}
.section-header {
text-align: center;
margin-bottom: 4rem;
}
.section-badge {
display: inline-flex;
align-items: center;
gap: 0.5rem;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 0.5rem 1.5rem;
border-radius: 50px;
font-size: 0.85rem;
font-weight: 600;
margin-bottom: 1rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.section-title {
font-family: 'Poppins', sans-serif;
font-size: 3rem;
font-weight: 700;
color: #1a202c;
margin-bottom: 1rem;
line-height: 1.2;
}
.section-description {
font-size: 1.2rem;
color: #4a5568;
max-width: 600px;
margin: 0 auto;
line-height: 1.6;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.feature-card {
background: white;
padding: 2.5rem;
border-radius: 20px;
text-align: center;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid #e2e8f0;
position: relative;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.feature-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(135deg, #667eea, #764ba2);
}
.feature-card:hover {
transform: translateY(-12px);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
border-color: #667eea;
}
.feature-icon {
font-size: 3.5rem;
margin-bottom: 1.5rem;
display: block;
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.1));
}
.feature-title {
font-family: 'Poppins', sans-serif;
font-size: 1.4rem;
font-weight: 600;
color: #1a202c;
margin-bottom: 1rem;
}
.feature-description {
color: #4a5568;
line-height: 1.6;
font-size: 1rem;
}
/* Main Content Section */
.main-content {
background: white;
margin: 3rem 2rem;
padding: 4rem;
border-radius: 24px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
}
.main-content::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 6px;
background: linear-gradient(135deg, #667eea, #764ba2, #6B73FF);
}
/* Input Section Styling */
.input-container {
max-width: 800px;
margin: 0 auto;
}
.stTextArea > div > div > textarea {
border-radius: 16px !important;
border: 2px solid #e2e8f0 !important;
padding: 1.5rem !important;
font-size: 1.1rem !important;
font-family: 'Inter', sans-serif !important;
transition: all 0.3s ease !important;
background: #fafafa !important;
resize: vertical !important;
min-height: 200px !important;
}
.stTextArea > div > div > textarea:focus {
border-color: #667eea !important;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1) !important;
background: white !important;
outline: none !important;
}
.stTextArea > div > div > textarea::placeholder {
color: #a0aec0 !important;
font-style: italic !important;
}
/* Enhanced Button Styling */
.stButton > button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
color: white !important;
border: none !important;
border-radius: 16px !important;
padding: 1rem 3rem !important;
font-size: 1.2rem !important;
font-weight: 600 !important;
font-family: 'Poppins', sans-serif !important;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4) !important;
width: 100% !important;
position: relative !important;
overflow: hidden !important;
}
.stButton > button:hover {
transform: translateY(-3px) !important;
box-shadow: 0 15px 35px rgba(102, 126, 234, 0.6) !important;
background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%) !important;
}
.stButton > button:active {
transform: translateY(-1px) !important;
}
/* Results Section */
.results-container {
margin-top: 3rem;
padding: 2rem;
background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%);
border-radius: 20px;
border: 1px solid #e2e8f0;
}
.result-card {
background: white;
padding: 2.5rem;
border-radius: 20px;
margin: 1.5rem 0;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
border-left: 6px solid transparent;
transition: all 0.3s ease;
}
.result-card:hover {
transform: translateY(-2px);
box-shadow: 0 12px 35px rgba(0, 0, 0, 0.12);
}
.prediction-badge {
display: inline-flex;
align-items: center;
gap: 0.75rem;
padding: 1rem 2rem;
border-radius: 50px;
font-weight: 700;
font-size: 1.1rem;
margin-bottom: 1rem;
}
.fake-news {
background: linear-gradient(135deg, #fed7d7 0%, #feb2b2 100%);
color: #c53030;
border-left-color: #e53e3e;
}
.real-news {
background: linear-gradient(135deg, #c6f6d5 0%, #9ae6b4 100%);
color: #2f855a;
border-left-color: #38a169;
}
.confidence-score {
font-size: 1.4rem;
font-weight: 700;
margin-left: auto;
}
/* Analysis Cards */
.analysis-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin: 2rem 0;
}
.analysis-card {
background: white;
padding: 2rem;
border-radius: 16px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
border-top: 4px solid #667eea;
}
.analysis-title {
font-family: 'Poppins', sans-serif;
font-size: 1.3rem;
font-weight: 600;
color: #1a202c;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.analysis-content {
color: #4a5568;
line-height: 1.6;
}
.analysis-list {
list-style: none;
padding: 0;
}
.analysis-list li {
padding: 0.5rem 0;
padding-left: 1.5rem;
position: relative;
border-bottom: 1px solid #f1f5f9;
}
.analysis-list li:before {
content: 'βœ“';
position: absolute;
left: 0;
color: #667eea;
font-weight: bold;
}
.analysis-list li:last-child {
border-bottom: none;
}
/* Chart Containers */
.chart-container {
background: white;
padding: 2rem;
border-radius: 16px;
margin: 1rem 0;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
border: 1px solid #f1f5f9;
}
/* Footer */
.footer {
background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%);
color: white;
padding: 4rem 2rem 2rem;
text-align: center;
margin-top: 5rem;
position: relative;
overflow: hidden;
}
.footer::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 6px;
background: linear-gradient(135deg, #667eea, #764ba2, #6B73FF);
}
.footer-content {
max-width: 1200px;
margin: 0 auto;
position: relative;
z-index: 2;
}
.footer-title {
font-family: 'Poppins', sans-serif;
font-size: 2rem;
font-weight: 700;
margin-bottom: 1rem;
background: linear-gradient(135deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.footer-text {
color: #cbd5e0;
margin-bottom: 2rem;
line-height: 1.7;
font-size: 1.1rem;
}
.footer-links {
display: flex;
justify-content: center;
gap: 3rem;
margin-bottom: 3rem;
flex-wrap: wrap;
}
.footer-link {
color: #cbd5e0;
text-decoration: none;
transition: all 0.3s ease;
font-weight: 500;
padding: 0.5rem 1rem;
border-radius: 8px;
}
.footer-link:hover {
color: white;
background: rgba(102, 126, 234, 0.2);
transform: translateY(-2px);
}
.footer-bottom {
border-top: 1px solid #4a5568;
padding-top: 2rem;
color: #a0aec0;
font-size: 0.95rem;
line-height: 1.6;
}
/* Loading Spinner Custom */
.stSpinner > div {
border-color: #667eea transparent #667eea transparent !important;
}
/* Responsive Design */
@media (max-width: 768px) {
.hero-title {
font-size: 3rem;
}
.hero-stats {
flex-direction: column;
gap: 1.5rem;
}
.features-grid {
grid-template-columns: 1fr;
}
.main-content {
margin: 2rem 1rem;
padding: 2rem;
}
.section-title {
font-size: 2.2rem;
}
.footer-links {
flex-direction: column;
gap: 1rem;
}
.analysis-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.hero-title {
font-size: 2.5rem;
}
.section-title {
font-size: 2rem;
}
.feature-card {
padding: 2rem 1.5rem;
}
}
</style>
""", unsafe_allow_html=True)
@st.cache_resource
def load_model_and_tokenizer():
"""Load the model and tokenizer (cached)."""
model = HybridFakeNewsDetector(
bert_model_name=BERT_MODEL_NAME,
lstm_hidden_size=LSTM_HIDDEN_SIZE,
lstm_num_layers=LSTM_NUM_LAYERS,
dropout_rate=DROPOUT_RATE
)
state_dict = torch.load(SAVED_MODELS_DIR / "final_model.pt", map_location=torch.device('cpu'))
model_state_dict = model.state_dict()
filtered_state_dict = {k: v for k, v in state_dict.items() if k in model_state_dict}
model.load_state_dict(filtered_state_dict, strict=False)
model.eval()
tokenizer = BertTokenizer.from_pretrained(BERT_MODEL_NAME)
return model, tokenizer
@st.cache_resource
def get_preprocessor():
"""Get the text preprocessor (cached)."""
return TextPreprocessor()
def predict_news(text):
"""Predict if the given news is fake or real."""
model, tokenizer = load_model_and_tokenizer()
preprocessor = get_preprocessor()
processed_text = preprocessor.preprocess_text(text)
encoding = tokenizer.encode_plus(
processed_text,
add_special_tokens=True,
max_length=MAX_SEQUENCE_LENGTH,
padding='max_length',
truncation=True,
return_attention_mask=True,
return_tensors='pt'
)
with torch.no_grad():
outputs = model(
encoding['input_ids'],
encoding['attention_mask']
)
probabilities = torch.softmax(outputs['logits'], dim=1)
prediction = torch.argmax(outputs['logits'], dim=1)
attention_weights = outputs['attention_weights']
attention_weights_np = attention_weights[0].cpu().numpy()
return {
'prediction': prediction.item(),
'label': 'FAKE' if prediction.item() == 1 else 'REAL',
'confidence': torch.max(probabilities, dim=1)[0].item(),
'probabilities': {
'REAL': probabilities[0][0].item(),
'FAKE': probabilities[0][1].item()
},
'attention_weights': attention_weights_np
}
def plot_confidence(probabilities):
"""Plot prediction confidence with enhanced styling."""
colors = ['#22c55e', '#ef4444']
fig = go.Figure(data=[
go.Bar(
x=list(probabilities.keys()),
y=list(probabilities.values()),
text=[f'{p:.1%}' for p in probabilities.values()],
textposition='auto',
textfont=dict(size=16, family="Poppins", color="white"),
marker=dict(
color=colors,
line=dict(color='rgba(255,255,255,0.3)', width=2),
pattern_shape="",
),
hovertemplate='<b>%{x}</b><br>Confidence: %{y:.1%}<extra></extra>',
width=[0.6, 0.6]
)
])
fig.update_layout(
title={
'text': 'πŸ“Š Prediction Confidence',
'x': 0.5,
'xanchor': 'center',
'font': {'size': 24, 'family': 'Poppins', 'color': '#1a202c'}
},
xaxis=dict(
title='Classification',
titlefont=dict(size=16, family='Inter', color='#4a5568'),
tickfont=dict(size=14, family='Inter', color='#4a5568'),
showgrid=False,
),
yaxis=dict(
title='Probability',
titlefont=dict(size=16, family='Inter', color='#4a5568'),
tickfont=dict(size=14, family='Inter', color='#4a5568'),
range=[0, 1],
tickformat='.0%',
showgrid=True,
gridcolor='rgba(0,0,0,0.05)',
),
template='plotly_white',
plot_bgcolor='rgba(0,0,0,0)',
paper_bgcolor='rgba(0,0,0,0)',
font={'family': 'Inter'},
margin=dict(l=50, r=50, t=80, b=50),
height=400
)
return fig
def plot_attention(text, attention_weights):
"""Plot attention weights with enhanced styling."""
tokens = text.split()[:20] # Limit to first 20 tokens for better visualization
attention_weights = attention_weights[:len(tokens)]
if isinstance(attention_weights, (list, np.ndarray)):
attention_weights = np.array(attention_weights).flatten()
# Normalize attention weights
if len(attention_weights) > 0 and max(attention_weights) > 0:
normalized_weights = attention_weights / max(attention_weights)
else:
normalized_weights = attention_weights
# Create gradient colors
colors = [f'rgba(102, 126, 234, {0.3 + 0.7 * float(w)})' for w in normalized_weights]
fig = go.Figure(data=[
go.Bar(
x=tokens,
y=attention_weights,
text=[f'{float(w):.3f}' for w in attention_weights],
textposition='auto',
textfont=dict(size=12, family="Inter", color="white"),
marker=dict(
color=colors,
line=dict(color='rgba(102, 126, 234, 0.8)', width=1),
),
hovertemplate='<b>%{x}</b><br>Attention: %{y:.3f}<extra></extra>',
)
])
fig.update_layout(
title={
'text': '🎯 Attention Weights Analysis',
'x': 0.5,
'xanchor': 'center',
'font': {'size': 24, 'family': 'Poppins', 'color': '#1a202c'}
},
xaxis=dict(
title='Words/Tokens',
titlefont=dict(size=16, family='Inter', color='#4a5568'),
tickfont=dict(size=12, family='Inter', color='#4a5568'),
tickangle=45,
showgrid=False,
),
yaxis=dict(
title='Attention Score',
titlefont=dict(size=16, family='Inter', color='#4a5568'),
tickfont=dict(size=14, family='Inter', color='#4a5568'),
showgrid=True,
gridcolor='rgba(0,0,0,0.05)',
),
template='plotly_white',
plot_bgcolor='rgba(0,0,0,0)',
paper_bgcolor='rgba(0,0,0,0)',
font={'family': 'Inter'},
margin=dict(l=50, r=50, t=80, b=100),
height=450
)
return fig
def main():
# Header Navigation
st.markdown("""
<div class="header-nav">
<div class="nav-brand">
πŸ›‘οΈ TruthCheck
</div>
</div>
""", unsafe_allow_html=True)
# Hero Section
st.markdown("""
<div class="hero-container">
<div class="hero-content">
<div class="hero-badge">
⚑ Powered by Advanced AI Technology
</div>
<h1 class="hero-title">πŸ›‘οΈ TruthCheck</h1>
<h2 style="font-size: 1.8rem; font-weight: 600; margin-bottom: 1rem; opacity: 0.9;">Advanced Fake News Detector</h2>
<p class="hero-subtitle">
πŸ” Leverage cutting-edge deep learning technology to instantly analyze and verify news articles.
Our hybrid BERT-BiLSTM model delivers precise, trustworthy results with detailed explanations.
</p>
<div class="hero-stats">
<div class="stat-item">
<span class="stat-number">95%+</span>
<span class="stat-label">Accuracy</span>
</div>
<div class="stat-item">
<span class="stat-number">&lt;3s</span>
<span class="stat-label">Analysis Time</span>
</div>
<div class="stat-item">
<span class="stat-number">24/7</span>
<span class="stat-label">Available</span>
</div>
</div>
</div>
</div>
""", unsafe_allow_html=True)
# Features Section
st.markdown("""
<div class="features-section">
<div class="section-header">
<div class="section-badge">
πŸš€ Advanced Features
</div>
<h2 class="section-title">Why Choose TruthCheck?</h2>
<p class="section-description">
Our state-of-the-art AI combines multiple advanced technologies to deliver unparalleled accuracy in fake news detection
</p>
</div>
<div class="features-grid">
<div class="feature-card">
<span class="feature-icon">πŸ€–</span>
<h3 class="feature-title">BERT Transformer</h3>
<p class="feature-description">
Utilizes state-of-the-art BERT transformer architecture for deep contextual understanding and semantic analysis of news content with unprecedented accuracy.
</p>
</div>
<div class="feature-card">
<span class="feature-icon">🧠</span>
<h3 class="feature-title">BiLSTM Networks</h3>
<p class="feature-description">
Advanced bidirectional LSTM networks capture sequential patterns, temporal dependencies, and linguistic structures in news articles for comprehensive analysis.
</p>
</div>
<div class="feature-card">
<span class="feature-icon">πŸ‘οΈ</span>
<h3 class="feature-title">Attention Mechanism</h3>
<p class="feature-description">
Sophisticated attention layers provide transparent insights into model decision-making, highlighting key phrases and suspicious content patterns.
</p>
</div>
<div class="feature-card">
<span class="feature-icon">⚑</span>
<h3 class="feature-title">Real-time Processing</h3>
<p class="feature-description">
Lightning-fast analysis delivers results in seconds, enabling immediate verification of news content without compromising accuracy or detail.
</p>
</div>
<div class="feature-card">
<span class="feature-icon">πŸ“Š</span>
<h3 class="feature-title">Confidence Scoring</h3>
<p class="feature-description">
Detailed confidence metrics and probability distributions provide clear insights into prediction reliability and uncertainty levels.
</p>
</div>
<div class="feature-card">
<span class="feature-icon">πŸ”’</span>
<h3 class="feature-title">Privacy Protected</h3>
<p class="feature-description">
Your data is processed securely with no storage or tracking. Complete privacy protection ensures your news analysis remains confidential.
</p>
</div>
</div>
</div>
""", unsafe_allow_html=True)
# Main Content Section
st.markdown("""
<div class="main-content">
<div class="section-header">
<div class="section-badge">
πŸ” AI Analysis
</div>
<h2 class="section-title">Analyze News Article</h2>
<p class="section-description">
πŸ“ Simply paste any news article below and our advanced AI will provide instant, detailed analysis with confidence scores, attention weights, and comprehensive insights.
</p>
</div>
<div class="input-container">
""", unsafe_allow_html=True)
# Input Section
news_text = st.text_area(
"",
height=250,
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.",
key="news_input",
help="Enter the full text of a news article for analysis. The more complete the article, the more accurate the analysis will be."
)
st.markdown("</div>", unsafe_allow_html=True)
# Enhanced Button Section
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
analyze_button = st.button(
"πŸ” Analyze Article with AI",
key="analyze_button",
help="Click to start AI-powered analysis of the news article"
)
if analyze_button:
if news_text and len(news_text.strip()) > 10:
with st.spinner("πŸ€– AI is analyzing the article... Please wait"):
try:
result = predict_news(news_text)
# Results Container
st.markdown('<div class="results-container">', unsafe_allow_html=True)
# Main Prediction Result
col1, col2 = st.columns([1, 1], gap="large")
with col1:
st.markdown("### 🎯 AI Prediction Result")
if result['label'] == 'FAKE':
st.markdown(f'''
<div class="result-card fake-news">
<div class="prediction-badge">
🚨 FAKE NEWS DETECTED
<span class="confidence-score">{result["confidence"]:.1%}</span>
</div>
<div style="font-size: 1.1rem; color: #c53030; line-height: 1.6;">
<strong>⚠️ Warning:</strong> Our AI model has identified this content as likely misinformation based on linguistic patterns, structural analysis, and content inconsistencies.
</div>
</div>
''', unsafe_allow_html=True)
else:
st.markdown(f'''
<div class="result-card real-news">
<div class="prediction-badge">
βœ… AUTHENTIC NEWS
<span class="confidence-score">{result["confidence"]:.1%}</span>
</div>
<div style="font-size: 1.1rem; color: #2f855a; line-height: 1.6;">
<strong>βœ“ Verified:</strong> This content appears to be legitimate news based on professional writing style, factual consistency, and structural integrity.
</div>
</div>
''', unsafe_allow_html=True)
with col2:
st.markdown("### πŸ“ˆ Confidence Breakdown")
st.markdown('<div class="chart-container">', unsafe_allow_html=True)
st.plotly_chart(plot_confidence(result['probabilities']), use_container_width=True)
st.markdown('</div>', unsafe_allow_html=True)
# Attention Analysis
st.markdown("### 🎯 AI Attention Analysis")
st.markdown("""
<p style="color: #4a5568; text-align: center; margin-bottom: 2rem; font-size: 1.1rem; line-height: 1.6;">
🧠 The visualization below reveals which words and phrases our AI model focused on during analysis.
<strong>Higher attention scores</strong> (darker colors) indicate words that significantly influenced the prediction.
</p>
""", unsafe_allow_html=True)
st.markdown('<div class="chart-container">', unsafe_allow_html=True)
st.plotly_chart(plot_attention(news_text, result['attention_weights']), use_container_width=True)
st.markdown('</div>', unsafe_allow_html=True)
# Detailed Analysis
st.markdown("### πŸ” Comprehensive AI Analysis")
if result['label'] == 'FAKE':
st.markdown("""
<div class="analysis-grid">
<div class="analysis-card">
<h4 class="analysis-title">⚠️ Misinformation Indicators</h4>
<div class="analysis-content">
<ul class="analysis-list">
<li><strong>Linguistic Anomalies:</strong> Detected language patterns commonly associated with fabricated content and misinformation campaigns</li>
<li><strong>Structural Inconsistencies:</strong> Identified irregular text flow, unusual formatting, or non-standard journalistic structure</li>
<li><strong>Content Reliability:</strong> Found potential factual inconsistencies, exaggerated claims, or misleading statements</li>
<li><strong>Emotional Manipulation:</strong> High attention on emotionally charged language designed to provoke strong reactions</li>
<li><strong>Source Credibility:</strong> Writing style and presentation lack hallmarks of professional journalism</li>
</ul>
</div>
</div>
<div class="analysis-card">
<h4 class="analysis-title">πŸ›‘οΈ Recommended Actions</h4>
<div class="analysis-content">
<ul class="analysis-list">
<li><strong>Verify Sources:</strong> Cross-reference information with multiple reputable news outlets and official sources</li>
<li><strong>Check Facts:</strong> Use fact-checking websites like Snopes, PolitiFact, or FactCheck.org for verification</li>
<li><strong>Avoid Sharing:</strong> Do not share this content until authenticity is confirmed through reliable sources</li>
<li><strong>Report Misinformation:</strong> Consider reporting to platform moderators if shared on social media</li>
<li><strong>Stay Informed:</strong> Follow trusted news sources for accurate information on this topic</li>
</ul>
</div>
</div>
</div>
""", unsafe_allow_html=True)
else:
st.markdown("""
<div class="analysis-grid">
<div class="analysis-card">
<h4 class="analysis-title">βœ… Authenticity Indicators</h4>
<div class="analysis-content">
<ul class="analysis-list">
<li><strong>Professional Language:</strong> Demonstrates standard journalistic writing style with balanced, objective reporting tone</li>
<li><strong>Structural Integrity:</strong> Follows conventional news article format with proper introduction, body, and conclusion</li>
<li><strong>Factual Consistency:</strong> Information appears coherent, logically structured, and factually consistent throughout</li>
<li><strong>Neutral Presentation:</strong> Maintains objectivity without excessive emotional language or bias indicators</li>
<li><strong>Credible Content:</strong> Contains specific details, proper context, and verifiable information patterns</li>
</ul>
</div>
</div>
<div class="analysis-card">
<h4 class="analysis-title">πŸ“‹ Best Practices</h4>
<div class="analysis-content">
<ul class="analysis-list">
<li><strong>Continue Verification:</strong> While likely authentic, always cross-reference important news from multiple sources</li>
<li><strong>Check Publication Date:</strong> Ensure the information is current and hasn't been superseded by newer developments</li>
<li><strong>Verify Author Credentials:</strong> Research the author's background and expertise in the subject matter</li>
<li><strong>Review Source Reputation:</strong> Confirm the publication's credibility and editorial standards</li>
<li><strong>Stay Updated:</strong> Monitor for any corrections, updates, or follow-up reporting on the topic</li>
</ul>
</div>
</div>
</div>
""", unsafe_allow_html=True)
# Technical Details
with st.expander("πŸ”§ Technical Analysis Details", expanded=False):
col1, col2, col3 = st.columns(3)
with col1:
st.metric(
label="🎯 Prediction Confidence",
value=f"{result['confidence']:.2%}",
help="Overall confidence in the AI's prediction"
)
with col2:
st.metric(
label="πŸ“Š REAL Probability",
value=f"{result['probabilities']['REAL']:.2%}",
help="Probability that the content is authentic news"
)
with col3:
st.metric(
label="⚠️ FAKE Probability",
value=f"{result['probabilities']['FAKE']:.2%}",
help="Probability that the content is fake news"
)
st.markdown("---")
st.markdown("""
**πŸ€– Model Information:**
- **Architecture:** Hybrid BERT + BiLSTM with Attention Mechanism
- **Training Data:** Extensive dataset of verified real and fake news articles
- **Features:** Contextual embeddings, sequential patterns, attention weights
- **Performance:** 95%+ accuracy on validation datasets
""")
st.markdown('</div>', unsafe_allow_html=True)
except Exception as e:
st.error(f"""
🚨 **Analysis Error Occurred**
We encountered an issue while analyzing your article. This might be due to:
- Technical server issues
- Content formatting problems
- Model loading difficulties
**Error Details:** {str(e)}
Please try again in a few moments or contact support if the issue persists.
""")
else:
st.markdown('''
<div class="main-content">
<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;">
<h3 style="margin-bottom: 1rem;">⚠️ Input Required</h3>
<p style="font-size: 1.1rem; line-height: 1.6;">
Please enter a news article (at least 10 words) to perform AI analysis.
<br><strong>πŸ’‘ Tip:</strong> Longer, complete articles provide more accurate results.
</p>
</div>
</div>
''', unsafe_allow_html=True)
st.markdown('</div>', unsafe_allow_html=True)
# Footer
st.markdown("""
<div class="footer">
<div class="footer-content">
<h3 class="footer-title">πŸ›‘οΈ TruthCheck AI</h3>
<p class="footer-text">
🌟 Empowering global communities with cutting-edge AI-driven news verification technology.
Built with advanced deep learning models, natural language processing, and transparent machine learning practices
to combat misinformation and promote media literacy worldwide.
</p>
<div class="footer-links">
<a href="#" class="footer-link">πŸ“– About TruthCheck</a>
<a href="#" class="footer-link">πŸ”¬ How It Works</a>
<a href="#" class="footer-link">πŸ“Š Accuracy Reports</a>
<a href="#" class="footer-link">πŸ”’ Privacy Policy</a>
<a href="#" class="footer-link">πŸ“ž Contact Support</a>
<a href="#" class="footer-link">πŸ†˜ Report Issues</a>
</div>
<div class="footer-bottom">
<p style="margin-bottom: 1rem;">
&copy; 2025 TruthCheck AI. Built with ❀️ using Streamlit, BERT, PyTorch, and Advanced Machine Learning.
</p>
<p>
<strong>πŸ” Disclaimer:</strong> This tool provides AI-based analysis for informational purposes.
Always verify important information through multiple reliable sources and exercise critical thinking.
Our AI model achieves high accuracy but is not infallible - human judgment remains essential.
</p>
</div>
</div>
</div>
""", unsafe_allow_html=True)
if __name__ == "__main__":
main()