areeba-sloth commited on
Commit
767bc54
Β·
verified Β·
1 Parent(s): 59995c4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -248
app.py CHANGED
@@ -78,14 +78,6 @@ st.markdown("""
78
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
79
  color: #856404 !important;
80
  }
81
- /* Section titles (bold black headings) */
82
- .section-title {
83
- font-size: 1.7rem;
84
- font-weight: 800;
85
- color: #000000 !important;
86
- margin-top: 2rem;
87
- margin-bottom: 1rem;
88
- }
89
 
90
  .verdict-mixed h3, .verdict-mixed p, .verdict-mixed strong {
91
  color: #856404 !important;
@@ -123,6 +115,7 @@ st.markdown("""
123
  border: 2px solid #dee2e6;
124
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
125
  }
 
126
  /* Fix input & textarea visibility */
127
  textarea, input {
128
  background-color: #f8f9fa !important;
@@ -135,6 +128,7 @@ st.markdown("""
135
  textarea::placeholder, input::placeholder {
136
  color: #6c757d !important;
137
  }
 
138
  .stat-box h2 {
139
  margin: 0 !important;
140
  font-size: 2.5rem !important;
@@ -148,43 +142,33 @@ st.markdown("""
148
  </style>
149
  """, unsafe_allow_html=True)
150
 
151
-
 
 
152
  class GoogleFactCheckAPI:
153
- """Google Fact Check Tools API Integration - IMPROVED VERSION"""
154
 
155
  def __init__(self, api_key: Optional[str] = None):
156
  self.api_key = api_key or os.environ.get('GOOGLE_API_KEY')
157
  self.base_url = "https://factchecktools.googleapis.com/v1alpha1/claims:search"
158
-
159
  if not self.api_key:
160
- st.warning("⚠️ Google API Key not found. Add it in Settings β†’ Repository secrets")
 
 
 
 
161
 
162
  def verify_claim(self, claim: str, language: str = "en") -> Dict:
163
- """
164
- Verify claim with IMPROVED search strategy
165
- """
166
  if not self.api_key:
167
- return {
168
- "status": "error",
169
- "message": "❌ API key not configured. Please add GOOGLE_API_KEY in Hugging Face Secrets."
170
- }
171
 
172
  try:
173
- # Try original query first
174
- params = {
175
- "key": self.api_key,
176
- "query": claim,
177
- "languageCode": language,
178
- "pageSize": 10 # Get more results
179
- }
180
-
181
  response = requests.get(self.base_url, params=params, timeout=15)
182
  response.raise_for_status()
183
  data = response.json()
184
 
185
- # If no results, try simplified query
186
  if "claims" not in data or len(data["claims"]) == 0:
187
- # Try extracting key terms
188
  simplified_query = self._simplify_claim(claim)
189
  if simplified_query != claim:
190
  params["query"] = simplified_query
@@ -193,17 +177,11 @@ class GoogleFactCheckAPI:
193
  data = response.json()
194
 
195
  if "claims" not in data or len(data["claims"]) == 0:
196
- return {
197
- "status": "no_results",
198
- "message": f"No fact-checks found for: '{claim}'"
199
- }
200
 
201
- # Process results
202
  results = []
203
  for claim_data in data["claims"]:
204
- claim_review = claim_data.get("claimReview", [])
205
-
206
- for review in claim_review:
207
  results.append({
208
  "claim_text": claim_data.get("text", ""),
209
  "claimant": claim_data.get("claimant", "Unknown"),
@@ -215,124 +193,85 @@ class GoogleFactCheckAPI:
215
  "language": review.get("languageCode", "en")
216
  })
217
 
218
- return {
219
- "status": "success",
220
- "claim": claim,
221
- "results": results,
222
- "count": len(results)
223
- }
224
-
225
  except requests.exceptions.HTTPError as e:
226
  if e.response.status_code == 403:
227
- return {
228
- "status": "error",
229
- "message": "❌ API key is invalid or Fact Check API is not enabled. Check Google Cloud Console."
230
- }
231
- return {
232
- "status": "error",
233
- "message": f"❌ HTTP Error: {str(e)}"
234
- }
235
  except requests.exceptions.RequestException as e:
236
- return {
237
- "status": "error",
238
- "message": f"❌ Network error: {str(e)}"
239
- }
240
  except Exception as e:
241
- return {
242
- "status": "error",
243
- "message": f"❌ Unexpected error: {str(e)}"
244
- }
245
 
246
  def _simplify_claim(self, claim: str) -> str:
247
- """Extract key terms from claim for better matching"""
248
- # Remove common words that don't help matching
249
- stop_words = ['the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been',
250
- 'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will',
251
- 'would', 'should', 'could', 'may', 'might', 'can']
252
-
253
  words = claim.lower().split()
254
  key_words = [w for w in words if w not in stop_words and len(w) > 2]
255
-
256
- return ' '.join(key_words[:5]) if key_words else claim # Max 5 key words
257
-
258
 
 
 
 
259
  def determine_verdict_color(rating: str) -> str:
260
- """Determine CSS class based on rating"""
261
  rating_lower = rating.lower()
262
-
263
  true_keywords = ["true", "correct", "accurate", "mostly true", "verified", "confirmed"]
264
  false_keywords = ["false", "incorrect", "inaccurate", "mostly false", "debunked", "fake", "pants on fire"]
265
  mixed_keywords = ["mixture", "mixed", "partially", "misleading", "unproven", "undetermined"]
266
-
267
- if any(keyword in rating_lower for keyword in true_keywords):
268
  return "verdict-true"
269
- elif any(keyword in rating_lower for keyword in false_keywords):
270
  return "verdict-false"
271
- elif any(keyword in rating_lower for keyword in mixed_keywords):
272
  return "verdict-mixed"
273
- else:
274
- return "verdict-unverified"
275
-
276
 
277
  def get_verdict_emoji(rating: str) -> str:
278
- """Get emoji based on verdict"""
279
- verdict_class = determine_verdict_color(rating)
280
-
281
- emoji_map = {
282
- "verdict-true": "βœ…",
283
- "verdict-false": "❌",
284
- "verdict-mixed": "⚠️",
285
- "verdict-unverified": "❓"
286
- }
287
-
288
- return emoji_map.get(verdict_class, "❓")
289
 
290
  def classify_rating(rating: str) -> str:
291
- """Classify rating into true/false/mixed/unverified"""
292
  r = rating.lower()
293
-
294
- if any(k in r for k in ["false", "fake", "pants on fire"]):
295
- return "false"
296
- elif any(k in r for k in ["true", "correct", "accurate"]):
297
- return "true"
298
- elif any(k in r for k in ["mixed", "misleading", "partially", "half", "mostly"]):
299
- return "mixed"
300
  return "unverified"
301
 
 
 
 
302
  def main():
303
- # Header with FIXED colors
304
  st.markdown('<div class="main-header">πŸ” VeriFact</div>', unsafe_allow_html=True)
305
  st.markdown('<div class="sub-header">AI-Powered Fact Checking β€’ Built by Areeba Fatima</div>', unsafe_allow_html=True)
306
-
307
  # Sidebar
308
  with st.sidebar:
309
  st.header("βš™οΈ Configuration")
310
-
311
- api_key_input = st.text_input(
312
- "Google API Key (Optional)",
313
- type="password",
314
- help="Leave empty to use Hugging Face Secrets"
315
- )
316
-
317
  st.markdown("---")
318
 
319
- st.success("""
320
- **VeriFact** verifies claims using Google's Fact Check Tools API against
321
- databases from PolitiFact, Snopes, FactCheck.org, and 50+ other sources.
322
- """)
 
 
323
 
324
  st.markdown("---")
325
-
326
- st.info("""
327
- **How to Use:**
328
- 1. Enter any claim
329
- 2. Click Verify
330
- 3. Review results
331
- 4. Check sources
332
- """)
 
 
 
333
 
334
  st.markdown("---")
335
-
336
  with st.expander("πŸ“ Example Claims to Try"):
337
  st.code("""
338
  βœ… TRUE:
@@ -355,33 +294,22 @@ def main():
355
  fact_checker = GoogleFactCheckAPI(api_key)
356
 
357
  # Main content
358
- st.markdown(
359
- '<div class="section-title">πŸ“ Enter Your Claim</div>',
360
- unsafe_allow_html=True
361
- )
362
 
363
- claim_text = st.text_area(
364
- "Claim to Verify",
365
- height=120,
366
- placeholder="Example: COVID-19 vaccines are safe and effective",
367
- help="Enter any factual claim you want to verify"
368
- )
369
-
370
- col1, col2, col3 = st.columns([2, 2, 3])
371
-
372
- with col1:
373
- verify_button = st.button("πŸ” Verify Claim", type="primary", use_container_width=True)
374
-
375
- with col2:
376
- clear_button = st.button("πŸ—‘οΈ Clear", use_container_width=True)
377
-
378
- if clear_button:
379
- st.rerun()
380
 
381
  # Process verification
382
  if verify_button:
383
  if not claim_text.strip():
384
- st.warning("⚠️ Please enter a claim to verify.")
 
 
 
 
385
  else:
386
  with st.spinner("πŸ”Ž Searching fact-check databases..."):
387
  start_time = time.time()
@@ -391,95 +319,73 @@ def main():
391
  st.markdown("---")
392
 
393
  if results["status"] == "error":
394
- st.error(results['message'])
395
- st.info("""
396
- **Troubleshooting:**
397
- 1. Make sure you added `GOOGLE_API_KEY` in Settings β†’ Repository secrets
398
- 2. Verify the API key is correct
399
- 3. Ensure Fact Check Tools API is enabled in Google Cloud Console
400
- """)
401
-
 
 
 
 
 
 
402
  elif results["status"] == "no_results":
403
- st.warning(results['message'])
404
- st.info("""
405
- **Why no results?**
406
- β€’ This specific claim may not have been fact-checked yet
407
- β€’ Try rephrasing (simpler is better)
408
- β€’ Try well-known claims like "The Earth is flat"
409
- β€’ Check spelling
410
-
411
- **Note:** Not all claims have fact-checks available. The database contains
412
- claims that have been verified by major fact-checking organizations.
413
- """)
414
-
 
 
 
 
 
415
  elif results["status"] == "success":
416
- st.success(f"βœ… Found {results['count']} fact-check(s) in {end_time - start_time:.2f}s")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
417
 
418
- # Display statistics
419
- st.markdown(
420
- '<div class="section-title">πŸ“Š Results</div>',
421
- unsafe_allow_html=True
422
- )
423
-
424
- st.info(
425
- "ℹ️ **Important:** VeriFact does not perform original fact-checking. "
426
- "It retrieves claims that have already been verified by professional, "
427
- "published fact-checking organizations approved by Google."
428
- )
429
- # Count ratings
430
  ratings = [r["rating"] for r in results["results"]]
431
-
432
  classified = [classify_rating(r) for r in ratings]
433
-
434
  true_count = classified.count("true")
435
  false_count = classified.count("false")
436
  mixed_count = classified.count("mixed")
437
-
438
- col1, col2, col3, col4 = st.columns(4)
439
-
440
- with col1:
441
- st.markdown(f"""
442
- <div class="stat-box">
443
- <h2 style="color: #28a745;">βœ… {true_count}</h2>
444
- <p>True/Accurate</p>
445
- </div>
446
- """, unsafe_allow_html=True)
447
-
448
- with col2:
449
- st.markdown(f"""
450
- <div class="stat-box">
451
- <h2 style="color: #dc3545;">❌ {false_count}</h2>
452
- <p>False/Incorrect</p>
453
- </div>
454
- """, unsafe_allow_html=True)
455
 
456
- with col3:
457
- st.markdown(f"""
458
- <div class="stat-box">
459
- <h2 style="color: #ffc107;">⚠️ {mixed_count}</h2>
460
- <p>Mixed/Misleading</p>
461
- </div>
462
- """, unsafe_allow_html=True)
463
-
464
- with col4:
465
- st.markdown(f"""
466
- <div class="stat-box">
467
- <h2 style="color: #6c757d;">πŸ“° {results['count']}</h2>
468
- <p>Total Sources</p>
469
- </div>
470
- """, unsafe_allow_html=True)
471
 
472
  st.markdown("---")
473
-
474
- st.markdown(
475
- '<div class="section-title">πŸ” Detailed Fact-Check Results</div>',
476
- unsafe_allow_html=True
477
- )
478
 
479
  for idx, result in enumerate(results["results"], 1):
480
  verdict_class = determine_verdict_color(result["rating"])
481
  emoji = get_verdict_emoji(result["rating"])
482
-
483
  st.markdown(f"""
484
  <div class="{verdict_class}">
485
  <h3>{emoji} Fact-Check #{idx}</h3>
@@ -493,36 +399,12 @@ def main():
493
  </div>
494
  """, unsafe_allow_html=True)
495
 
496
- # Export options
497
  st.markdown("---")
498
- st.markdown(
499
- '<div class="section-title">πŸ“„ Report</div>',
500
- unsafe_allow_html=True
501
- )
502
-
503
- # Create export data
504
- export_text = f"""VERIFACT - CLAIM VERIFICATION REPORT
505
- Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
506
-
507
- CLAIM: {claim_text}
508
-
509
- SUMMARY:
510
- - Total Fact-Checks: {results['count']}
511
- - True/Accurate: {true_count}
512
- - False/Incorrect: {false_count}
513
- - Mixed/Misleading: {mixed_count}
514
-
515
- DETAILED RESULTS:
516
- """
517
- for idx, result in enumerate(results["results"], 1):
518
- export_text += f"""
519
- {idx}. {result["publisher"]}
520
- Rating: {result["rating"]}
521
- URL: {result["url"]}
522
- Claimant: {result["claimant"]}
523
- Date: {result["claim_date"]}
524
- Title: {result["title"]}
525
- """
526
 
527
  st.download_button(
528
  label="πŸ“„ Download Report",
@@ -535,13 +417,12 @@ DETAILED RESULTS:
535
  # Footer
536
  st.markdown("---")
537
  st.markdown("""
538
- <div style="text-align: center; color: #666; padding: 2rem 0;">
539
- <p style="font-size: 1.1rem;"><strong>VeriFact</strong> | Powered by Google Fact Check Tools API</p>
540
  <p>Built by <strong>Areeba Fatima</strong> with Python & Streamlit</p>
541
- <p style="font-size: 0.85rem; color: #999;">⚠️ Always verify important claims from multiple sources. This tool is for informational purposes.</p>
542
  </div>
543
  """, unsafe_allow_html=True)
544
 
545
-
546
  if __name__ == "__main__":
547
  main()
 
78
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
79
  color: #856404 !important;
80
  }
 
 
 
 
 
 
 
 
81
 
82
  .verdict-mixed h3, .verdict-mixed p, .verdict-mixed strong {
83
  color: #856404 !important;
 
115
  border: 2px solid #dee2e6;
116
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
117
  }
118
+
119
  /* Fix input & textarea visibility */
120
  textarea, input {
121
  background-color: #f8f9fa !important;
 
128
  textarea::placeholder, input::placeholder {
129
  color: #6c757d !important;
130
  }
131
+
132
  .stat-box h2 {
133
  margin: 0 !important;
134
  font-size: 2.5rem !important;
 
142
  </style>
143
  """, unsafe_allow_html=True)
144
 
145
+ # ==============================
146
+ # Google Fact Check API Class
147
+ # ==============================
148
  class GoogleFactCheckAPI:
149
+ """Google Fact Check Tools API Integration"""
150
 
151
  def __init__(self, api_key: Optional[str] = None):
152
  self.api_key = api_key or os.environ.get('GOOGLE_API_KEY')
153
  self.base_url = "https://factchecktools.googleapis.com/v1alpha1/claims:search"
 
154
  if not self.api_key:
155
+ st.markdown("""
156
+ <div class="verdict-mixed">
157
+ <p>⚠️ Google API Key not found. Add it in Settings β†’ Repository secrets</p>
158
+ </div>
159
+ """, unsafe_allow_html=True)
160
 
161
  def verify_claim(self, claim: str, language: str = "en") -> Dict:
 
 
 
162
  if not self.api_key:
163
+ return {"status": "error", "message": "❌ API key not configured. Please add GOOGLE_API_KEY in Hugging Face Secrets."}
 
 
 
164
 
165
  try:
166
+ params = {"key": self.api_key, "query": claim, "languageCode": language, "pageSize": 10}
 
 
 
 
 
 
 
167
  response = requests.get(self.base_url, params=params, timeout=15)
168
  response.raise_for_status()
169
  data = response.json()
170
 
 
171
  if "claims" not in data or len(data["claims"]) == 0:
 
172
  simplified_query = self._simplify_claim(claim)
173
  if simplified_query != claim:
174
  params["query"] = simplified_query
 
177
  data = response.json()
178
 
179
  if "claims" not in data or len(data["claims"]) == 0:
180
+ return {"status": "no_results", "message": f"No fact-checks found for: '{claim}'"}
 
 
 
181
 
 
182
  results = []
183
  for claim_data in data["claims"]:
184
+ for review in claim_data.get("claimReview", []):
 
 
185
  results.append({
186
  "claim_text": claim_data.get("text", ""),
187
  "claimant": claim_data.get("claimant", "Unknown"),
 
193
  "language": review.get("languageCode", "en")
194
  })
195
 
196
+ return {"status": "success", "claim": claim, "results": results, "count": len(results)}
197
+
 
 
 
 
 
198
  except requests.exceptions.HTTPError as e:
199
  if e.response.status_code == 403:
200
+ return {"status": "error", "message": "❌ API key is invalid or Fact Check API is not enabled. Check Google Cloud Console."}
201
+ return {"status": "error", "message": f"❌ HTTP Error: {str(e)}"}
 
 
 
 
 
 
202
  except requests.exceptions.RequestException as e:
203
+ return {"status": "error", "message": f"❌ Network error: {str(e)}"}
 
 
 
204
  except Exception as e:
205
+ return {"status": "error", "message": f"❌ Unexpected error: {str(e)}"}
 
 
 
206
 
207
  def _simplify_claim(self, claim: str) -> str:
208
+ stop_words = ['the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
209
+ 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'should',
210
+ 'could', 'may', 'might', 'can']
 
 
 
211
  words = claim.lower().split()
212
  key_words = [w for w in words if w not in stop_words and len(w) > 2]
213
+ return ' '.join(key_words[:5]) if key_words else claim
 
 
214
 
215
+ # ==============================
216
+ # Helper Functions
217
+ # ==============================
218
  def determine_verdict_color(rating: str) -> str:
 
219
  rating_lower = rating.lower()
 
220
  true_keywords = ["true", "correct", "accurate", "mostly true", "verified", "confirmed"]
221
  false_keywords = ["false", "incorrect", "inaccurate", "mostly false", "debunked", "fake", "pants on fire"]
222
  mixed_keywords = ["mixture", "mixed", "partially", "misleading", "unproven", "undetermined"]
223
+ if any(k in rating_lower for k in true_keywords):
 
224
  return "verdict-true"
225
+ elif any(k in rating_lower for k in false_keywords):
226
  return "verdict-false"
227
+ elif any(k in rating_lower for k in mixed_keywords):
228
  return "verdict-mixed"
229
+ return "verdict-unverified"
 
 
230
 
231
  def get_verdict_emoji(rating: str) -> str:
232
+ return {"verdict-true":"βœ…","verdict-false":"❌","verdict-mixed":"⚠️","verdict-unverified":"❓"}.get(determine_verdict_color(rating),"❓")
 
 
 
 
 
 
 
 
 
 
233
 
234
  def classify_rating(rating: str) -> str:
 
235
  r = rating.lower()
236
+ if any(k in r for k in ["false","fake","pants on fire"]): return "false"
237
+ if any(k in r for k in ["true","correct","accurate"]): return "true"
238
+ if any(k in r for k in ["mixed","misleading","partially","half","mostly"]): return "mixed"
 
 
 
 
239
  return "unverified"
240
 
241
+ # ==============================
242
+ # Main App
243
+ # ==============================
244
  def main():
 
245
  st.markdown('<div class="main-header">πŸ” VeriFact</div>', unsafe_allow_html=True)
246
  st.markdown('<div class="sub-header">AI-Powered Fact Checking β€’ Built by Areeba Fatima</div>', unsafe_allow_html=True)
247
+
248
  # Sidebar
249
  with st.sidebar:
250
  st.header("βš™οΈ Configuration")
251
+ api_key_input = st.text_input("Google API Key (Optional)", type="password", help="Leave empty to use Hugging Face Secrets")
 
 
 
 
 
 
252
  st.markdown("---")
253
 
254
+ st.markdown("""
255
+ <div class="verdict-unverified">
256
+ <p>ℹ️ <strong>VeriFact</strong> verifies claims using Google's Fact Check Tools API against
257
+ databases from PolitiFact, Snopes, FactCheck.org, and 50+ other sources.</p>
258
+ </div>
259
+ """, unsafe_allow_html=True)
260
 
261
  st.markdown("---")
262
+ st.markdown("""
263
+ <div class="verdict-unverified">
264
+ <p>ℹ️ <strong>How to Use:</strong></p>
265
+ <ul>
266
+ <li>Enter any claim</li>
267
+ <li>Click Verify</li>
268
+ <li>Review results</li>
269
+ <li>Check sources</li>
270
+ </ul>
271
+ </div>
272
+ """, unsafe_allow_html=True)
273
 
274
  st.markdown("---")
 
275
  with st.expander("πŸ“ Example Claims to Try"):
276
  st.code("""
277
  βœ… TRUE:
 
294
  fact_checker = GoogleFactCheckAPI(api_key)
295
 
296
  # Main content
297
+ st.markdown('<div class="section-title">πŸ“ Enter Your Claim</div>', unsafe_allow_html=True)
298
+ claim_text = st.text_area("Claim to Verify", height=120, placeholder="Example: COVID-19 vaccines are safe and effective", help="Enter any factual claim you want to verify")
 
 
299
 
300
+ col1, col2, col3 = st.columns([2,2,3])
301
+ with col1: verify_button = st.button("πŸ” Verify Claim", type="primary", use_container_width=True)
302
+ with col2: clear_button = st.button("πŸ—‘οΈ Clear", use_container_width=True)
303
+ if clear_button: st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
304
 
305
  # Process verification
306
  if verify_button:
307
  if not claim_text.strip():
308
+ st.markdown("""
309
+ <div class="verdict-mixed">
310
+ <p>⚠️ Please enter a claim to verify.</p>
311
+ </div>
312
+ """, unsafe_allow_html=True)
313
  else:
314
  with st.spinner("πŸ”Ž Searching fact-check databases..."):
315
  start_time = time.time()
 
319
  st.markdown("---")
320
 
321
  if results["status"] == "error":
322
+ st.markdown(f"""
323
+ <div class="verdict-false">
324
+ <p>❌ {results['message']}</p>
325
+ </div>
326
+ <div class="verdict-unverified">
327
+ <p>ℹ️ <strong>Troubleshooting:</strong></p>
328
+ <ul>
329
+ <li>Make sure you added <code>GOOGLE_API_KEY</code> in Settings β†’ Repository secrets</li>
330
+ <li>Verify the API key is correct</li>
331
+ <li>Ensure Fact Check Tools API is enabled in Google Cloud Console</li>
332
+ </ul>
333
+ </div>
334
+ """, unsafe_allow_html=True)
335
+
336
  elif results["status"] == "no_results":
337
+ st.markdown(f"""
338
+ <div class="verdict-mixed">
339
+ <p>⚠️ {results['message']}</p>
340
+ </div>
341
+ <div class="verdict-unverified">
342
+ <p>ℹ️ <strong>Why no results?</strong></p>
343
+ <ul>
344
+ <li>This specific claim may not have been fact-checked yet</li>
345
+ <li>Try rephrasing (simpler is better)</li>
346
+ <li>Try well-known claims like "The Earth is flat"</li>
347
+ <li>Check spelling</li>
348
+ </ul>
349
+ <p><strong>Note:</strong> Not all claims have fact-checks available. The database contains
350
+ claims that have been verified by major fact-checking organizations.</p>
351
+ </div>
352
+ """, unsafe_allow_html=True)
353
+
354
  elif results["status"] == "success":
355
+ st.markdown(f"""
356
+ <div class="verdict-true">
357
+ <h3>βœ… Found {results['count']} fact-check(s)</h3>
358
+ <p>⏱ Time taken: {end_time - start_time:.2f}s</p>
359
+ </div>
360
+ """, unsafe_allow_html=True)
361
+
362
+ st.markdown('<div class="section-title">πŸ“Š Results</div>', unsafe_allow_html=True)
363
+ st.markdown("""
364
+ <div class="verdict-unverified">
365
+ <p>ℹ️ <strong>Important:</strong> VeriFact does not perform original fact-checking.
366
+ It retrieves claims that have already been verified by professional,
367
+ published fact-checking organizations approved by Google.</p>
368
+ </div>
369
+ """, unsafe_allow_html=True)
370
 
 
 
 
 
 
 
 
 
 
 
 
 
371
  ratings = [r["rating"] for r in results["results"]]
 
372
  classified = [classify_rating(r) for r in ratings]
 
373
  true_count = classified.count("true")
374
  false_count = classified.count("false")
375
  mixed_count = classified.count("mixed")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
 
377
+ col1, col2, col3, col4 = st.columns(4)
378
+ with col1: st.markdown(f"""<div class="stat-box"><h2 style="color:#28a745;">βœ… {true_count}</h2><p>True/Accurate</p></div>""", unsafe_allow_html=True)
379
+ with col2: st.markdown(f"""<div class="stat-box"><h2 style="color:#dc3545;">❌ {false_count}</h2><p>False/Incorrect</p></div>""", unsafe_allow_html=True)
380
+ with col3: st.markdown(f"""<div class="stat-box"><h2 style="color:#ffc107;">⚠️ {mixed_count}</h2><p>Mixed/Misleading</p></div>""", unsafe_allow_html=True)
381
+ with col4: st.markdown(f"""<div class="stat-box"><h2 style="color:#6c757d;">πŸ“° {results['count']}</h2><p>Total Sources</p></div>""", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
382
 
383
  st.markdown("---")
384
+ st.markdown('<div class="section-title">πŸ” Detailed Fact-Check Results</div>', unsafe_allow_html=True)
 
 
 
 
385
 
386
  for idx, result in enumerate(results["results"], 1):
387
  verdict_class = determine_verdict_color(result["rating"])
388
  emoji = get_verdict_emoji(result["rating"])
 
389
  st.markdown(f"""
390
  <div class="{verdict_class}">
391
  <h3>{emoji} Fact-Check #{idx}</h3>
 
399
  </div>
400
  """, unsafe_allow_html=True)
401
 
402
+ # Export Report
403
  st.markdown("---")
404
+ st.markdown('<div class="section-title">πŸ“„ Report</div>', unsafe_allow_html=True)
405
+ export_text = f"VERIFACT - CLAIM VERIFICATION REPORT\nGenerated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\nCLAIM: {claim_text}\n\nSUMMARY:\n- Total Fact-Checks: {results['count']}\n- True/Accurate: {true_count}\n- False/Incorrect: {false_count}\n- Mixed/Misleading: {mixed_count}\n\nDETAILED RESULTS:\n"
406
+ for idx, result in enumerate(results["results"],1):
407
+ export_text += f"\n{idx}. {result['publisher']}\n Rating: {result['rating']}\n URL: {result['url']}\n Claimant: {result['claimant']}\n Date: {result['claim_date']}\n Title: {result['title']}\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
 
409
  st.download_button(
410
  label="πŸ“„ Download Report",
 
417
  # Footer
418
  st.markdown("---")
419
  st.markdown("""
420
+ <div style="text-align:center;color:#666;padding:2rem 0;">
421
+ <p style="font-size:1.1rem;"><strong>VeriFact</strong> | Powered by Google Fact Check Tools API</p>
422
  <p>Built by <strong>Areeba Fatima</strong> with Python & Streamlit</p>
423
+ <p style="font-size:0.85rem;color:#999;">⚠️ Always verify important claims from multiple sources. This tool is for informational purposes.</p>
424
  </div>
425
  """, unsafe_allow_html=True)
426
 
 
427
  if __name__ == "__main__":
428
  main()