KhaqanNasir commited on
Commit
3a44358
·
verified ·
1 Parent(s): 2ddd46f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -430
app.py CHANGED
@@ -1,464 +1,192 @@
1
- import streamlit as st
2
- import torch
3
- import pandas as pd
4
- import numpy as np
5
- from pathlib import Path
6
  import sys
7
- import plotly.express as px
8
- import plotly.graph_objects as go
9
- from transformers import BertTokenizer
10
- import nltk
11
-
12
- # Download required NLTK data
13
- try:
14
- nltk.data.find('tokenizers/punkt')
15
- except LookupError:
16
- nltk.download('punkt')
17
- try:
18
- nltk.data.find('corpora/stopwords')
19
- except LookupError:
20
- nltk.download('stopwords')
21
- try:
22
- nltk.data.find('tokenizers/punkt_tab')
23
- except LookupError:
24
- nltk.download('punkt_tab')
25
- try:
26
- nltk.data.find('corpora/wordnet')
27
- except LookupError:
28
- nltk.download('wordnet')
29
-
30
- # Add project root to Python path
31
- project_root = Path(__file__).parent.parent
32
- sys.path.append(str(project_root))
33
 
34
- 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 streamlined 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;800&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: #1a202c;
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: 1rem;
70
- }
71
-
72
- /* Header */
73
- .header {
74
- padding: 1rem 0;
75
- text-align: center;
76
- }
77
-
78
- .header-title {
79
- font-size: 2rem;
80
- font-weight: 800;
81
- color: #1a202c;
82
- display: inline-flex;
83
- align-items: center;
84
- gap: 0.5rem;
85
- }
86
-
87
- /* Hero Section */
88
- .hero {
89
- display: flex;
90
- align-items: center;
91
- gap: 2rem;
92
- margin-bottom: 2rem;
93
- }
94
-
95
- .hero-left {
96
- flex: 1;
97
  padding: 1rem;
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: 8px;
111
- }
112
-
113
- .hero-title {
114
- font-size: 2.5rem;
115
- font-weight: 700;
116
- color: #1a202c;
117
- margin-bottom: 0.5rem;
118
- }
119
-
120
- .hero-text {
121
- font-size: 1rem;
122
- color: #4a5568;
123
- line-height: 1.5;
124
- max-width: 450px;
125
- }
126
-
127
- /* About Section */
128
- .about-section {
129
- margin-bottom: 2rem;
130
- text-align: center;
131
- }
132
-
133
- .about-title {
134
- font-size: 1.8rem;
135
  font-weight: 600;
136
- color: #1a202c;
137
- margin-bottom: 0.5rem;
138
- }
139
-
140
- .about-text {
141
- font-size: 1rem;
142
- color: #4a5568;
143
- line-height: 1.5;
144
- max-width: 600px;
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: 8px !important;
156
- border: 1px solid #d1d5db !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
- transition: all 0.2s ease !important;
163
- }
164
-
165
- .stTextArea > div > div > textarea:focus {
166
- border-color: #6366f1 !important;
167
- box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1) !important;
168
- outline: none !important;
169
- }
170
-
171
- .stTextArea > div > div > textarea::placeholder {
172
- color: #9ca3af !important;
173
  }
174
-
175
- /* Button Styling */
176
- .stButton > button {
177
- background: #6366f1 !important;
178
- color: white !important;
179
- border-radius: 8px !important;
180
- padding: 0.75rem 2rem !important;
181
- font-size: 1rem !important;
182
- font-weight: 600 !important;
183
- font-family: 'Inter', sans-serif !important;
184
- transition: all 0.2s ease !important;
185
- border: none !important;
186
- width: 100% !important;
187
- }
188
-
189
- .stButton > button:hover {
190
- background: #4f46e5 !important;
191
- transform: translateY(-1px) !important;
192
  }
193
-
194
- /* Results Section */
195
- .results-container {
196
- margin-top: 1rem;
197
- padding: 1rem;
198
  border-radius: 8px;
 
199
  }
200
-
201
- .result-card {
 
 
 
 
 
 
 
202
  padding: 1rem;
203
  border-radius: 8px;
204
- border-left: 4px solid transparent;
205
  margin-bottom: 1rem;
 
206
  }
207
-
208
- .fake-news {
209
- background: #fef2f2;
210
- border-left-color: #ef4444;
211
  }
212
-
213
- .real-news {
214
- background: #ecfdf5;
215
- border-left-color: #10b981;
216
  }
217
-
218
- .prediction-badge {
219
- font-weight: 600;
220
- font-size: 1rem;
221
- margin-bottom: 0.5rem;
222
- display: flex;
223
- align-items: center;
224
  gap: 0.5rem;
225
  }
226
-
227
- .confidence-score {
228
- font-weight: 600;
229
- margin-left: auto;
230
- font-size: 1rem;
231
- }
232
-
233
- /* Chart Containers */
234
- .chart-container {
235
- padding: 1rem;
236
  border-radius: 8px;
237
- margin: 1rem 0;
 
 
238
  }
239
-
240
- /* Footer */
241
- .footer {
242
- margin-top: 2rem;
243
- padding: 1rem 0;
244
- text-align: center;
245
- border-top: 1px solid #e5e7eb;
 
 
246
  }
247
  </style>
248
  """, unsafe_allow_html=True)
249
 
250
- @st.cache_resource
251
- def load_model_and_tokenizer():
252
- """Load the model and tokenizer (cached)."""
253
- model = HybridFakeNewsDetector(
254
- bert_model_name=BERT_MODEL_NAME,
255
- lstm_hidden_size=LSTM_HIDDEN_SIZE,
256
- lstm_num_layers=LSTM_NUM_LAYERS,
257
- dropout_rate=DROPOUT_RATE
258
- )
259
- state_dict = torch.load(SAVED_MODELS_DIR / "final_model.pt", map_location=torch.device('cpu'))
260
- model_state_dict = model.state_dict()
261
- filtered_state_dict = {k: v for k, v in state_dict.items() if k in model_state_dict}
262
- model.load_state_dict(filtered_state_dict, strict=False)
263
- model.eval()
264
- tokenizer = BertTokenizer.from_pretrained(BERT_MODEL_NAME)
265
- return model, tokenizer
266
 
267
  @st.cache_resource
268
- def get_preprocessor():
269
- """Get the text preprocessor (cached)."""
270
- return TextPreprocessor()
271
-
272
- def predict_news(text):
273
- """Predict if the given news is fake or real."""
274
- model, tokenizer = load_model_and_tokenizer()
275
- preprocessor = get_preprocessor()
276
- processed_text = preprocessor.preprocess_text(text)
277
- encoding = tokenizer.encode_plus(
278
- processed_text,
279
- add_special_tokens=True,
280
- max_length=MAX_SEQUENCE_LENGTH,
281
- padding='max_length',
282
- truncation=True,
283
- return_attention_mask=True,
284
- return_tensors='pt'
285
- )
286
- with torch.no_grad():
287
- outputs = model(
288
- encoding['input_ids'],
289
- encoding['attention_mask']
290
- )
291
- probabilities = torch.softmax(outputs['logits'], dim=1)
292
- prediction = torch.argmax(outputs['logits'], dim=1)
293
- attention_weights = outputs['attention_weights']
294
- attention_weights_np = attention_weights[0].cpu().numpy()
295
- return {
296
- 'prediction': prediction.item(),
297
- 'label': 'FAKE' if prediction.item() == 1 else 'REAL',
298
- 'confidence': torch.max(probabilities, dim=1)[0].item(),
299
- 'probabilities': {
300
- 'REAL': probabilities[0][0].item(),
301
- 'FAKE': probabilities[0][1].item()
302
- },
303
- 'attention_weights': attention_weights_np
304
- }
305
-
306
- def plot_confidence(probabilities):
307
- """Plot prediction confidence with simplified styling."""
308
- fig = go.Figure(data=[
309
- go.Bar(
310
- x=list(probabilities.keys()),
311
- y=list(probabilities.values()),
312
- text=[f'{p:.1%}' for p in probabilities.values()],
313
- textposition='auto',
314
- marker=dict(
315
- color=['#10b981', '#ef4444'],
316
- line=dict(color='#ffffff', width=1),
317
- ),
318
- )
319
- ])
320
- fig.update_layout(
321
- title={'text': 'Prediction Confidence', 'x': 0.5, 'xanchor': 'center', 'font': {'size': 18}},
322
- xaxis=dict(title='Classification', titlefont={'size': 12}, tickfont={'size': 10}),
323
- yaxis=dict(title='Probability', range=[0, 1], tickformat='.0%', titlefont={'size': 12}, tickfont={'size': 10}),
324
- template='plotly_white',
325
- height=300,
326
- margin=dict(t=60, b=60)
327
- )
328
- return fig
329
-
330
- def plot_attention(text, attention_weights):
331
- """Plot attention weights with simplified styling."""
332
- tokens = text.split()[:20]
333
- attention_weights = attention_weights[:len(tokens)]
334
- if isinstance(attention_weights, (list, np.ndarray)):
335
- attention_weights = np.array(attention_weights).flatten()
336
- normalized_weights = attention_weights / max(attention_weights) if max(attention_weights) > 0 else attention_weights
337
- colors = [f'rgba(99, 102, 241, {0.4 + 0.6 * float(w)})' for w in normalized_weights]
338
- fig = go.Figure(data=[
339
- go.Bar(
340
- x=tokens,
341
- y=attention_weights,
342
- text=[f'{float(w):.3f}' for w in attention_weights],
343
- textposition='auto',
344
- marker=dict(color=colors),
345
- )
346
- ])
347
- fig.update_layout(
348
- title={'text': 'Attention Weights', 'x': 0.5, 'xanchor': 'center', 'font': {'size': 18}},
349
- xaxis=dict(title='Words', tickangle=45, titlefont={'size': 12}, tickfont={'size': 10}),
350
- yaxis=dict(title='Attention Score', titlefont={'size': 12}, tickfont={'size': 10}),
351
- template='plotly_white',
352
- height=350,
353
- margin=dict(t=60, b=80)
354
- )
355
- return fig
356
-
357
- def main():
358
- # Header
359
- st.markdown("""
360
- <div class="header">
361
- <div class="container">
362
- <h1 class="header-title">🛡️ TruthCheck</h1>
363
- </div>
364
- </div>
365
- """, unsafe_allow_html=True)
366
-
367
- # Hero Section
368
- st.markdown("""
369
- <div class="container">
370
- <div class="hero">
371
- <div class="hero-left">
372
- <h2 class="hero-title">Instant Fake News Detection</h2>
373
- <p class="hero-text">
374
- Verify news articles with our AI-powered tool, driven by BERT and BiLSTM for fast and accurate authenticity analysis.
375
- </p>
376
- </div>
377
- <div class="hero-right">
378
- <img src="/static/hero.png" alt="TruthCheck Illustration">
379
- </div>
380
- </div>
381
- </div>
382
- """, unsafe_allow_html=True)
383
-
384
- # About Section
385
- st.markdown("""
386
- <div class="container">
387
- <div class="about-section">
388
- <h2 class="about-title">About TruthCheck</h2>
389
- <p class="about-text">
390
- TruthCheck uses a hybrid BERT-BiLSTM model to detect fake news with high accuracy. Paste an article below for instant analysis.
391
- </p>
392
- </div>
393
- </div>
394
- """, unsafe_allow_html=True)
395
-
396
- # Input Section
397
- st.markdown('<div class="container"><div class="input-container">', unsafe_allow_html=True)
398
- news_text = st.text_area(
399
- "Analyze a News Article",
400
- height=150,
401
- placeholder="Paste your news article here for instant AI analysis...",
402
- key="news_input"
403
- )
404
- st.markdown('</div>', unsafe_allow_html=True)
405
 
406
- # Analyze Button
407
- st.markdown('<div class="container">', unsafe_allow_html=True)
408
- col1, col2, col3 = st.columns([1, 2, 1])
409
- with col2:
410
- analyze_button = st.button("🔍 Analyze Now", key="analyze_button")
411
- st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
 
413
- if analyze_button:
414
- if news_text and len(news_text.strip()) > 10:
415
- with st.spinner("Analyzing article..."):
416
- try:
417
- result = predict_news(news_text)
418
- st.markdown('<div class="container"><div class="results-container">', unsafe_allow_html=True)
419
-
420
- # Prediction Result
421
- col1, col2 = st.columns([1, 1], gap="medium")
422
- with col1:
423
- if result['label'] == 'FAKE':
424
- st.markdown(f'''
425
- <div class="result-card fake-news">
426
- <div class="prediction-badge">🚨 Fake News Detected <span class="confidence-score">{result["confidence"]:.1%}</span></div>
427
- <p>Our AI has identified this content as likely misinformation based on linguistic patterns and content analysis.</p>
428
- </div>
429
- ''', unsafe_allow_html=True)
430
- else:
431
- st.markdown(f'''
432
- <div class="result-card real-news">
433
- <div class="prediction-badge">✅ Authentic News <span class="confidence-score">{result["confidence"]:.1%}</span></div>
434
- <p>This content appears to be legitimate based on professional writing style and factual consistency.</p>
435
- </div>
436
- ''', unsafe_allow_html=True)
437
-
438
- with col2:
439
- st.markdown('<div class="chart-container">', unsafe_allow_html=True)
440
- st.plotly_chart(plot_confidence(result['probabilities']), use_container_width=True)
441
- st.markdown('</div>', unsafe_allow_html=True)
442
-
443
- # Attention Analysis
444
- st.markdown('<div class="chart-container">', unsafe_allow_html=True)
445
- st.plotly_chart(plot_attention(news_text, result['attention_weights']), use_container_width=True)
446
- st.markdown('</div></div></div>', unsafe_allow_html=True)
447
- except Exception as e:
448
- st.markdown('<div class="container">', unsafe_allow_html=True)
449
- st.error(f"Error: {str(e)}. Please try again or contact support.")
450
- st.markdown('</div>', unsafe_allow_html=True)
451
- else:
452
- st.markdown('<div class="container">', unsafe_allow_html=True)
453
- st.error("Please enter a news article (at least 10 words) for analysis.")
454
- st.markdown('</div>', unsafe_allow_html=True)
455
 
456
- # Footer
457
- st.markdown("""
458
- <div class="footer">
459
- <p style="text-align: center; font-weight: 600; font-size: 16px;">💻 Developed with ❤️ using Streamlit | © 2025</p>
460
- </div>
461
- """, unsafe_allow_html=True)
462
 
463
  if __name__ == "__main__":
464
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import sys
2
+ from pathlib import Path
3
+ import os
4
+ import gdown
5
+ import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
+ # Set page config - must be first Streamlit command
8
+ st.set_page_config(
9
+ page_title="TruthCheck - Advanced Fake News Detector",
10
+ page_icon="🛡️",
11
+ layout="wide",
12
+ initial_sidebar_state="expanded"
13
+ )
14
 
15
+ # Custom CSS for modern styling
16
  st.markdown("""
17
  <style>
18
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap');
19
+
20
+ body {
21
+ font-family: 'Poppins', sans-serif;
22
+ background-color: #FFFFFF;
23
+ color: #333333;
24
+ }
25
+
26
+ .sidebar .sidebar-content {
27
+ background-color: #F4F7FA;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  padding: 1rem;
29
  }
30
+
31
+ .stButton>button {
32
+ background-color: #4B5EAA;
33
+ color: white;
 
 
 
 
 
 
 
34
  border-radius: 8px;
35
+ padding: 0.5rem 1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  font-weight: 600;
37
+ transition: background-color 0.3s;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
+
40
+ .stButton>button:hover {
41
+ background-color: #3A4A8C;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  }
43
+
44
+ .stTextArea textarea {
45
+ border: 1px solid #E0E0E0;
 
 
46
  border-radius: 8px;
47
+ padding: 1rem;
48
  }
49
+
50
+ .hero-section {
51
+ background-color: #F4F7FA;
52
+ padding: 2rem;
53
+ border-radius: 12px;
54
+ margin-bottom: 2rem;
55
+ }
56
+
57
+ .flash-message {
58
  padding: 1rem;
59
  border-radius: 8px;
 
60
  margin-bottom: 1rem;
61
+ font-weight: 600;
62
  }
63
+
64
+ .success-message {
65
+ background-color: #E6F4EA;
66
+ color: #2E7D32;
67
  }
68
+
69
+ .error-message {
70
+ background-color: #FEE2E2;
71
+ color: #B71C1C;
72
  }
73
+
74
+ /* Enhanced sidebar styling */
75
+ .stRadio > div {
 
 
 
 
76
  gap: 0.5rem;
77
  }
78
+
79
+ .stRadio > div > label {
80
+ padding: 0.5rem 1rem;
 
 
 
 
 
 
 
81
  border-radius: 8px;
82
+ transition: all 0.3s ease;
83
+ cursor: pointer;
84
+ font-weight: 500;
85
  }
86
+
87
+ .stRadio > div > label:hover {
88
+ background-color: #E8F0FE;
89
+ transform: translateX(5px);
90
+ }
91
+
92
+ .stRadio > div > label[data-checked="true"] {
93
+ background-color: #4B5EAA;
94
+ color: white;
95
  }
96
  </style>
97
  """, unsafe_allow_html=True)
98
 
99
+ MODEL_PATH = "models/saved/final_model.pt"
100
+ GOOGLE_DRIVE_FILE_ID = "1xhYKuC5_Yri3mm3Ejt-SpB2WAVUTJvc_"
101
+ GOOGLE_DRIVE_URL = f"https://drive.google.com/uc?id={GOOGLE_DRIVE_FILE_ID}"
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  @st.cache_resource
104
+ def download_model():
105
+ """Download model from Google Drive if not exists."""
106
+ if not os.path.exists(MODEL_PATH):
107
+ os.makedirs(os.path.dirname(MODEL_PATH), exist_ok=True)
108
+ with st.spinner("Downloading model from Google Drive..."):
109
+ try:
110
+ gdown.download(GOOGLE_DRIVE_URL, MODEL_PATH, quiet=False)
111
+ st.markdown('<div class="flash-message success-message">Model downloaded successfully!</div>', unsafe_allow_html=True)
112
+ except Exception as e:
113
+ st.markdown(f'<div class="flash-message error-message">Failed to download model: {str(e)}</div>', unsafe_allow_html=True)
114
+ st.markdown('<div class="flash-message error-message">Please check your Google Drive link and make sure the file is publicly accessible.</div>', unsafe_allow_html=True)
115
+ return False
116
+ return True
117
+
118
+ # Add src directory to Python path
119
+ src_path = Path(__file__).parent / "src"
120
+ sys.path.append(str(src_path))
121
+
122
+ # Enhanced Sidebar navigation with icons
123
+ st.sidebar.markdown("""
124
+ <div style="text-align: center; margin-bottom: 2rem;">
125
+ <div style="font-size: 2.5rem; margin-bottom: 0.5rem;">🛡️</div>
126
+ <h1 style="color: #4B5EAA; font-size: 1.5rem; font-weight: 600; margin-bottom: 0.5rem; line-height: 1.2;">
127
+ TruthCheck
128
+ </h1>
129
+ <p style="color: #666; font-size: 0.9rem; margin: 0; font-weight: 300; line-height: 1.3;">
130
+ Advanced Fake News Detector
131
+ </p>
132
+ </div>
133
+ """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
 
135
+ st.sidebar.markdown("---")
136
+
137
+ # Navigation with icons
138
+ page = st.sidebar.radio(
139
+ "Navigate",
140
+ [
141
+ "🏠 Home",
142
+ "ℹ️ About",
143
+ "📋 Terms of Use",
144
+ "🔒 Privacy Policy",
145
+ "👥 Contact"
146
+ ],
147
+ label_visibility="collapsed",
148
+ key="navigation"
149
+ )
150
+
151
+ # Add some spacing and additional info
152
+ st.sidebar.markdown("---")
153
+ st.sidebar.markdown("""
154
+ <div style="text-align: center; padding: 1.5rem; background: linear-gradient(135deg, #F8F9FA 0%, #E8F0FE 100%); border-radius: 12px; margin-top: 1rem; border: 1px solid #E0E7FF;">
155
+ <div style="font-size: 2rem; margin-bottom: 0.8rem;">🔍</div>
156
+ <p style="font-size: 0.85rem; color: #4B5EAA; margin: 0; font-weight: 500; line-height: 1.4;">
157
+ Protecting you from misinformation with AI-powered detection
158
+ </p>
159
+ </div>
160
+ """, unsafe_allow_html=True)
161
 
162
+ # Add footer info
163
+ st.sidebar.markdown("""
164
+ <div style="position: fixed; bottom: 1rem; left: 1rem; right: 1rem; text-align: center; padding: 0.5rem; background-color: rgba(255,255,255,0.9); border-radius: 8px; border-top: 1px solid #E0E0E0;">
165
+ <p style="font-size: 0.7rem; color: #888; margin: 0;">
166
+ © 2025 TruthCheck | AI-Powered
167
+ </p>
168
+ </div>
169
+ """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
+ # Clean up the page variable to remove icons for the conditional logic
172
+ page_clean = page.split(" ", 1)[1] if " " in page else page
 
 
 
 
173
 
174
  if __name__ == "__main__":
175
+ if page_clean == "Home":
176
+ if download_model():
177
+ from src.app import main
178
+ main()
179
+ else:
180
+ st.markdown('<div class="flash-message error-message">Cannot start the application without the model file.</div>', unsafe_allow_html=True)
181
+ elif page_clean == "About":
182
+ from src.about import main
183
+ main()
184
+ elif page_clean == "Terms of Use":
185
+ from src.terms_of_use import main
186
+ main()
187
+ elif page_clean == "Privacy Policy":
188
+ from src.privacy_policy import main
189
+ main()
190
+ elif page_clean == "Contact":
191
+ from src.contact import main
192
+ main()