lightmate commited on
Commit
c14313e
Β·
verified Β·
1 Parent(s): 22259c7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +370 -8
app.py CHANGED
@@ -8,6 +8,11 @@ import gradio as gr
8
  import uvicorn
9
  import time
10
  import uuid
 
 
 
 
 
11
  from fastapi import FastAPI, Request, Depends
12
  from fastapi.responses import RedirectResponse
13
  from starlette.middleware.sessions import SessionMiddleware
@@ -25,6 +30,13 @@ except Exception as e:
25
  print("Please ensure all environment variables are set correctly.")
26
  raise
27
 
 
 
 
 
 
 
 
28
  # Create FastAPI app
29
  app = FastAPI(title="DGaze - News Verification")
30
 
@@ -102,6 +114,295 @@ def get_base_url(request: Request) -> str:
102
  base_url = base_url.replace('http://', 'https://')
103
  return base_url
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  # Authentication routes - using specific HTTP methods to avoid conflicts
106
  @app.get('/api/login')
107
  @app.post('/api/login')
@@ -166,9 +467,9 @@ async def auth(request: Request):
166
  print(f"DEBUG: Auth error: {e}")
167
  return RedirectResponse(url='/')
168
 
169
- # Verification function with trial tracking and loading states
170
  def verify_news_with_trial_check(input_text: str, request: gr.Request, progress=gr.Progress()) -> str:
171
- """Verification function with free trial tracking and loading progress."""
172
  if not input_text.strip():
173
  return "Please enter some text or URL to verify"
174
 
@@ -185,11 +486,30 @@ def verify_news_with_trial_check(input_text: str, request: gr.Request, progress=
185
  progress(0.3, desc="πŸ” Analyzing content...")
186
  time.sleep(0.5)
187
 
188
- progress(0.7, desc="🧠 Processing with AI...")
189
  data = api_client.verify_news(input_text)
190
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  progress(1.0, desc="βœ… Verification complete!")
192
- return format_verification_results(data)
 
 
 
 
 
 
 
193
 
194
  # Check if user is authenticated
195
  user = get_user(fastapi_request)
@@ -243,8 +563,29 @@ def verify_news_with_trial_check(input_text: str, request: gr.Request, progress=
243
  progress(0.7, desc="🧠 Processing with AI...")
244
  data = api_client.verify_news(input_text)
245
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  progress(0.9, desc="πŸ“Š Formatting results...")
247
- result = format_verification_results(data)
 
 
 
 
 
248
 
249
  progress(1.0, desc="βœ… Verification complete!")
250
 
@@ -257,7 +598,7 @@ def verify_news_with_trial_check(input_text: str, request: gr.Request, progress=
257
  </p>
258
  </div>
259
  """
260
- return trial_info + result
261
  else:
262
  # Authenticated user - proceed normally with progress
263
  progress(0.3, desc="πŸ” Analyzing content...")
@@ -269,11 +610,32 @@ def verify_news_with_trial_check(input_text: str, request: gr.Request, progress=
269
  progress(0.7, desc="🧠 Processing with AI...")
270
  data = api_client.verify_news(input_text)
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  progress(0.9, desc="πŸ“Š Formatting results...")
273
- result = format_verification_results(data)
 
 
 
 
 
274
 
275
  progress(1.0, desc="βœ… Verification complete!")
276
- return result
277
 
278
  except Exception as e:
279
  print(f"ERROR: {e}")
 
8
  import uvicorn
9
  import time
10
  import uuid
11
+ import asyncio
12
+ import aiohttp
13
+ import json
14
+ import re
15
+ from concurrent.futures import ThreadPoolExecutor, as_completed
16
  from fastapi import FastAPI, Request, Depends
17
  from fastapi.responses import RedirectResponse
18
  from starlette.middleware.sessions import SessionMiddleware
 
30
  print("Please ensure all environment variables are set correctly.")
31
  raise
32
 
33
+ # DeBERTa API Configuration from environment
34
+ DEBERTA_API_URL = os.getenv('DEBERTA_API_URL', 'https://rahulkc-dev--deberta-fever-vllm-pattern-serve.modal.run')
35
+ DEBERTA_API_KEY = os.getenv('DEBERTA_API_KEY', 'deberta-fever-secret-key')
36
+
37
+ print(f"DEBUG: DeBERTa API URL: {DEBERTA_API_URL}")
38
+ print(f"DEBUG: DeBERTa API Key: {'***' + DEBERTA_API_KEY[-4:] if DEBERTA_API_KEY else 'Not set'}")
39
+
40
  # Create FastAPI app
41
  app = FastAPI(title="DGaze - News Verification")
42
 
 
114
  base_url = base_url.replace('http://', 'https://')
115
  return base_url
116
 
117
+ # DeBERTa API Functions
118
+ async def call_deberta_api_async(evidence: str, claim: str, session_timeout: int = 30) -> dict:
119
+ """Async call to DeBERTa FEVER API for fact verification."""
120
+ try:
121
+ headers = {
122
+ "Authorization": f"Bearer {DEBERTA_API_KEY}",
123
+ "Content-Type": "application/json"
124
+ }
125
+
126
+ payload = {
127
+ "messages": [
128
+ {
129
+ "role": "user",
130
+ "content": f"Evidence: {evidence} Claim: {claim}"
131
+ }
132
+ ],
133
+ "model": "MoritzLaurer/DeBERTa-v3-base-mnli-fever-anli"
134
+ }
135
+
136
+ timeout = aiohttp.ClientTimeout(total=session_timeout)
137
+ async with aiohttp.ClientSession(timeout=timeout) as session:
138
+ async with session.post(
139
+ f"{DEBERTA_API_URL}/v1/chat/completions",
140
+ headers=headers,
141
+ json=payload
142
+ ) as response:
143
+ if response.status == 200:
144
+ result = await response.json()
145
+ content = result["choices"][0]["message"]["content"]
146
+
147
+ # Parse the response to extract verdict and confidence
148
+ verdict = "UNKNOWN"
149
+ confidence = 0.0
150
+
151
+ if "βœ… SUPPORTED" in content:
152
+ verdict = "SUPPORTED"
153
+ elif "❌ CONTRADICTED" in content:
154
+ verdict = "CONTRADICTED"
155
+ elif "πŸ€” NEUTRAL" in content:
156
+ verdict = "NEUTRAL"
157
+
158
+ # Extract confidence percentage
159
+ confidence_match = re.search(r'(\d+\.?\d*)%', content)
160
+ if confidence_match:
161
+ confidence = float(confidence_match.group(1))
162
+
163
+ # Calculate truthfulness score based on verdict and confidence
164
+ if verdict == "SUPPORTED":
165
+ truthfulness_score = confidence # High confidence support = high truthfulness
166
+ elif verdict == "CONTRADICTED":
167
+ truthfulness_score = 100 - confidence # High confidence contradiction = low truthfulness
168
+ else: # NEUTRAL
169
+ truthfulness_score = 50 # Neutral claims get middle truthfulness score
170
+
171
+ return {
172
+ "success": True,
173
+ "verdict": verdict,
174
+ "confidence": confidence,
175
+ "truthfulness_score": truthfulness_score,
176
+ "raw_response": content,
177
+ "claim": claim,
178
+ "evidence": evidence
179
+ }
180
+ else:
181
+ return {
182
+ "success": False,
183
+ "error": f"API returned status {response.status}",
184
+ "claim": claim,
185
+ "evidence": evidence
186
+ }
187
+
188
+ except Exception as e:
189
+ return {
190
+ "success": False,
191
+ "error": str(e),
192
+ "claim": claim,
193
+ "evidence": evidence
194
+ }
195
+
196
+ def call_deberta_api_sync(evidence: str, claim: str) -> dict:
197
+ """Synchronous wrapper for DeBERTa API call."""
198
+ loop = asyncio.new_event_loop()
199
+ asyncio.set_event_loop(loop)
200
+ try:
201
+ result = loop.run_until_complete(call_deberta_api_async(evidence, claim))
202
+ return result
203
+ finally:
204
+ loop.close()
205
+
206
+ def extract_claims_and_evidence(verification_data: dict) -> list:
207
+ """Extract claims and evidence from verification pipeline results."""
208
+ claims_evidence_pairs = []
209
+
210
+ try:
211
+ # Try to extract from the verification pipeline results
212
+ # This will depend on your existing API structure
213
+
214
+ # Example extraction - adapt this to your actual data structure
215
+ if 'claims' in verification_data:
216
+ claims = verification_data['claims']
217
+ evidence_text = verification_data.get('evidence', verification_data.get('sources', ''))
218
+
219
+ for claim in claims:
220
+ claims_evidence_pairs.append({
221
+ 'claim': claim,
222
+ 'evidence': evidence_text
223
+ })
224
+
225
+ # Fallback: try to extract from other possible structures
226
+ elif 'pipeline_results' in verification_data:
227
+ pipeline_data = verification_data['pipeline_results']
228
+
229
+ # Extract claims from step 2 (if available)
230
+ if len(pipeline_data) > 1 and 'claims' in pipeline_data[1]:
231
+ claims = pipeline_data[1]['claims']
232
+
233
+ # Extract evidence from step 1 (sources)
234
+ evidence_text = ""
235
+ if len(pipeline_data) > 0 and 'sources' in pipeline_data[0]:
236
+ sources = pipeline_data[0]['sources']
237
+ evidence_text = " ".join([source.get('snippet', '') for source in sources[:3]])
238
+
239
+ for claim in claims:
240
+ claims_evidence_pairs.append({
241
+ 'claim': claim,
242
+ 'evidence': evidence_text
243
+ })
244
+
245
+ # If no structured claims found, create a general claim from input
246
+ if not claims_evidence_pairs and 'input_text' in verification_data:
247
+ input_text = verification_data['input_text']
248
+ # Use a simple heuristic to create evidence from sources
249
+ evidence_text = "General knowledge and web sources"
250
+ if 'sources' in verification_data:
251
+ sources = verification_data['sources']
252
+ evidence_text = " ".join([source.get('snippet', '') for source in sources[:3]])
253
+
254
+ claims_evidence_pairs.append({
255
+ 'claim': input_text[:500], # Limit claim length
256
+ 'evidence': evidence_text
257
+ })
258
+
259
+ except Exception as e:
260
+ print(f"ERROR extracting claims and evidence: {e}")
261
+ # Fallback to empty list
262
+ pass
263
+
264
+ return claims_evidence_pairs
265
+
266
+ def process_deberta_results_parallel(claims_evidence_pairs: list, max_workers: int = 3) -> list:
267
+ """Process DeBERTa API calls in parallel."""
268
+ if not claims_evidence_pairs:
269
+ return []
270
+
271
+ deberta_results = []
272
+
273
+ # Limit the number of parallel requests to avoid overwhelming the API
274
+ with ThreadPoolExecutor(max_workers=min(max_workers, len(claims_evidence_pairs))) as executor:
275
+ # Submit all tasks
276
+ future_to_pair = {
277
+ executor.submit(call_deberta_api_sync, pair['evidence'], pair['claim']): pair
278
+ for pair in claims_evidence_pairs[:5] # Limit to 5 claims max
279
+ }
280
+
281
+ # Collect results as they complete
282
+ for future in as_completed(future_to_pair, timeout=45):
283
+ try:
284
+ result = future.result()
285
+ deberta_results.append(result)
286
+ except Exception as e:
287
+ pair = future_to_pair[future]
288
+ deberta_results.append({
289
+ "success": False,
290
+ "error": str(e),
291
+ "claim": pair['claim'],
292
+ "evidence": pair['evidence']
293
+ })
294
+
295
+ return deberta_results
296
+
297
+ def format_deberta_results(deberta_results: list) -> str:
298
+ """Format DeBERTa results for display."""
299
+ if not deberta_results:
300
+ return ""
301
+
302
+ html = """
303
+ <div style="background: #f8f9fa; border: 1px solid #e9ecef; border-radius: 8px; padding: 1.5rem; margin: 1rem 0;">
304
+ <h3 style="margin: 0 0 1rem 0; color: #495057; font-size: 1.2rem; display: flex; align-items: center;">
305
+ 🧠 AI Fact-Checking Analysis (DeBERTa FEVER)
306
+ </h3>
307
+ """
308
+
309
+ successful_results = [r for r in deberta_results if r.get('success', False)]
310
+ failed_results = [r for r in deberta_results if not r.get('success', False)]
311
+
312
+ if successful_results:
313
+ # Calculate overall score
314
+ verdicts = [r['verdict'] for r in successful_results]
315
+ confidences = [r['confidence'] for r in successful_results]
316
+ avg_confidence = sum(confidences) / len(confidences) if confidences else 0
317
+
318
+ # Count verdicts
319
+ supported_count = verdicts.count('SUPPORTED')
320
+ contradicted_count = verdicts.count('CONTRADICTED')
321
+ neutral_count = verdicts.count('NEUTRAL')
322
+
323
+ # Calculate average truthfulness score
324
+ truthfulness_scores = [r.get('truthfulness_score', 50) for r in successful_results]
325
+ avg_truthfulness = sum(truthfulness_scores) / len(truthfulness_scores) if truthfulness_scores else 50
326
+
327
+ # Overall assessment
328
+ if supported_count > contradicted_count:
329
+ overall_verdict = "MOSTLY SUPPORTED"
330
+ verdict_color = "#28a745"
331
+ verdict_icon = "βœ…"
332
+ elif contradicted_count > supported_count:
333
+ overall_verdict = "MOSTLY CONTRADICTED"
334
+ verdict_color = "#dc3545"
335
+ verdict_icon = "❌"
336
+ else:
337
+ overall_verdict = "MIXED/NEUTRAL"
338
+ verdict_color = "#ffc107"
339
+ verdict_icon = "πŸ€”"
340
+
341
+ html += f"""
342
+ <div style="background: {verdict_color}; color: white; padding: 1rem; border-radius: 6px; margin-bottom: 1rem; text-align: center;">
343
+ <div style="font-size: 1.5rem; font-weight: bold; margin-bottom: 0.5rem;">
344
+ {verdict_icon} {overall_verdict}
345
+ </div>
346
+ <div style="font-size: 1rem; opacity: 0.9;">
347
+ Average Confidence: {avg_confidence:.1f}% | Truthfulness: {avg_truthfulness:.1f}% | Claims Analyzed: {len(successful_results)}
348
+ </div>
349
+ <div style="font-size: 0.9rem; opacity: 0.8; margin-top: 0.5rem;">
350
+ βœ… {supported_count} Supported β€’ ❌ {contradicted_count} Contradicted β€’ πŸ€” {neutral_count} Neutral
351
+ </div>
352
+ </div>
353
+ """
354
+
355
+ # Individual results
356
+ html += "<div style='margin-top: 1rem;'><h4 style='margin-bottom: 0.5rem; color: #495057;'>Individual Claim Analysis:</h4>"
357
+
358
+ for i, result in enumerate(successful_results, 1):
359
+ verdict = result['verdict']
360
+ confidence = result['confidence']
361
+ truthfulness_score = result.get('truthfulness_score', 50)
362
+ claim = result['claim'][:150] + "..." if len(result['claim']) > 150 else result['claim']
363
+
364
+ # Choose colors and icons
365
+ if verdict == "SUPPORTED":
366
+ color = "#d4edda"
367
+ border_color = "#c3e6cb"
368
+ icon = "βœ…"
369
+ elif verdict == "CONTRADICTED":
370
+ color = "#f8d7da"
371
+ border_color = "#f5c6cb"
372
+ icon = "❌"
373
+ else:
374
+ color = "#fff3cd"
375
+ border_color = "#ffeaa7"
376
+ icon = "πŸ€”"
377
+
378
+ html += f"""
379
+ <div style="background: {color}; border: 1px solid {border_color}; border-radius: 4px; padding: 0.75rem; margin: 0.5rem 0;">
380
+ <div style="font-weight: 600; margin-bottom: 0.25rem; color: #495057;">
381
+ {icon} Claim {i}: {verdict} ({confidence:.1f}% confidence | {truthfulness_score:.1f}% truthfulness)
382
+ </div>
383
+ <div style="font-size: 0.9rem; color: #6c757d; font-style: italic;">
384
+ "{claim}"
385
+ </div>
386
+ </div>
387
+ """
388
+
389
+ html += "</div>"
390
+
391
+ if failed_results:
392
+ html += f"""
393
+ <div style="background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px; padding: 0.75rem; margin: 1rem 0;">
394
+ <div style="font-weight: 600; color: #721c24; margin-bottom: 0.25rem;">
395
+ ⚠️ Some claims could not be analyzed ({len(failed_results)} failed)
396
+ </div>
397
+ <div style="font-size: 0.9rem; color: #721c24;">
398
+ DeBERTa API may be temporarily unavailable for some requests.
399
+ </div>
400
+ </div>
401
+ """
402
+
403
+ html += "</div>"
404
+ return html
405
+
406
  # Authentication routes - using specific HTTP methods to avoid conflicts
407
  @app.get('/api/login')
408
  @app.post('/api/login')
 
467
  print(f"DEBUG: Auth error: {e}")
468
  return RedirectResponse(url='/')
469
 
470
+ # Verification function with trial tracking, loading states, and DeBERTa integration
471
  def verify_news_with_trial_check(input_text: str, request: gr.Request, progress=gr.Progress()) -> str:
472
+ """Verification function with free trial tracking, loading progress, and DeBERTa fact-checking."""
473
  if not input_text.strip():
474
  return "Please enter some text or URL to verify"
475
 
 
486
  progress(0.3, desc="πŸ” Analyzing content...")
487
  time.sleep(0.5)
488
 
489
+ progress(0.6, desc="🧠 Processing with AI...")
490
  data = api_client.verify_news(input_text)
491
 
492
+ # Add input text to data for DeBERTa processing
493
+ data['input_text'] = input_text
494
+
495
+ progress(0.8, desc="πŸ€– Running DeBERTa fact-checking...")
496
+
497
+ # Extract claims and evidence
498
+ claims_evidence_pairs = extract_claims_and_evidence(data)
499
+ deberta_results = []
500
+
501
+ if claims_evidence_pairs and DEBERTA_API_URL:
502
+ deberta_results = process_deberta_results_parallel(claims_evidence_pairs)
503
+
504
  progress(1.0, desc="βœ… Verification complete!")
505
+
506
+ # Format main results
507
+ main_result = format_verification_results(data)
508
+
509
+ # Add DeBERTa results if available
510
+ deberta_html = format_deberta_results(deberta_results) if deberta_results else ""
511
+
512
+ return main_result + deberta_html
513
 
514
  # Check if user is authenticated
515
  user = get_user(fastapi_request)
 
563
  progress(0.7, desc="🧠 Processing with AI...")
564
  data = api_client.verify_news(input_text)
565
 
566
+ # Add input text to data for DeBERTa processing
567
+ data['input_text'] = input_text
568
+
569
+ progress(0.8, desc="πŸ€– Running DeBERTa fact-checking...")
570
+
571
+ # Extract claims and evidence
572
+ claims_evidence_pairs = extract_claims_and_evidence(data)
573
+ deberta_results = []
574
+
575
+ if claims_evidence_pairs and DEBERTA_API_URL:
576
+ try:
577
+ deberta_results = process_deberta_results_parallel(claims_evidence_pairs)
578
+ except Exception as e:
579
+ print(f"DeBERTa processing error: {e}")
580
+ # Continue without DeBERTa results
581
+
582
  progress(0.9, desc="πŸ“Š Formatting results...")
583
+
584
+ # Format main results
585
+ main_result = format_verification_results(data)
586
+
587
+ # Add DeBERTa results if available
588
+ deberta_html = format_deberta_results(deberta_results) if deberta_results else ""
589
 
590
  progress(1.0, desc="βœ… Verification complete!")
591
 
 
598
  </p>
599
  </div>
600
  """
601
+ return trial_info + main_result + deberta_html
602
  else:
603
  # Authenticated user - proceed normally with progress
604
  progress(0.3, desc="πŸ” Analyzing content...")
 
610
  progress(0.7, desc="🧠 Processing with AI...")
611
  data = api_client.verify_news(input_text)
612
 
613
+ # Add input text to data for DeBERTa processing
614
+ data['input_text'] = input_text
615
+
616
+ progress(0.8, desc="πŸ€– Running DeBERTa fact-checking...")
617
+
618
+ # Extract claims and evidence
619
+ claims_evidence_pairs = extract_claims_and_evidence(data)
620
+ deberta_results = []
621
+
622
+ if claims_evidence_pairs and DEBERTA_API_URL:
623
+ try:
624
+ deberta_results = process_deberta_results_parallel(claims_evidence_pairs)
625
+ except Exception as e:
626
+ print(f"DeBERTa processing error: {e}")
627
+ # Continue without DeBERTa results
628
+
629
  progress(0.9, desc="πŸ“Š Formatting results...")
630
+
631
+ # Format main results
632
+ main_result = format_verification_results(data)
633
+
634
+ # Add DeBERTa results if available
635
+ deberta_html = format_deberta_results(deberta_results) if deberta_results else ""
636
 
637
  progress(1.0, desc="βœ… Verification complete!")
638
+ return main_result + deberta_html
639
 
640
  except Exception as e:
641
  print(f"ERROR: {e}")