Arko007 commited on
Commit
cf7f1b6
Β·
verified Β·
1 Parent(s): cb42cb5

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +502 -816
src/streamlit_app.py CHANGED
@@ -1,12 +1,12 @@
1
- # Fix HuggingFace cache permissions - MUST BE AT TOP
2
  import os
3
  import tempfile
 
4
 
5
- # Set writable cache directories
6
- temp_dir = tempfile.gettempdir()
7
- os.environ['HF_HOME'] = temp_dir
8
- os.environ['TRANSFORMERS_CACHE'] = temp_dir
9
- os.environ['HF_HUB_CACHE'] = temp_dir
10
 
11
  import streamlit as st
12
  import torch
@@ -46,431 +46,355 @@ if GOOGLE_API_KEY and GENAI_AVAILABLE:
46
  try:
47
  genai.configure(api_key=GOOGLE_API_KEY)
48
  API_CONFIGURED = True
49
- except Exception as e:
50
  API_CONFIGURED = False
51
  else:
52
  API_CONFIGURED = False
53
 
54
  # ==============================================================================
55
- # 🎨 ENHANCED CSS STYLING
56
  # ==============================================================================
57
- def load_custom_css():
58
- """Load enhanced CSS styling"""
59
- css_content = """
60
- <style>
61
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
62
-
63
- .stApp {
64
- background: linear-gradient(135deg, #0f0f23 0%, #1a1a3a 100%);
65
- color: #f1f5f9;
66
- font-family: 'Inter', sans-serif;
67
- }
68
-
69
- .main-title {
70
- font-size: clamp(2.5rem, 5vw, 4rem);
71
- background: linear-gradient(135deg, #6366f1, #0ea5e9);
72
- -webkit-background-clip: text;
73
- -webkit-text-fill-color: transparent;
74
- text-align: center;
75
- margin: 2rem 0;
76
- font-weight: 800;
77
- animation: glow 3s ease-in-out infinite alternate;
78
- }
79
-
80
- @keyframes glow {
81
- from { filter: drop-shadow(0 0 20px rgba(99, 102, 241, 0.3)); }
82
- to { filter: drop-shadow(0 0 40px rgba(99, 102, 241, 0.6)); }
83
- }
84
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  .hero-container {
86
- background: rgba(42, 42, 84, 0.3);
87
- backdrop-filter: blur(20px);
88
- border-radius: 24px;
89
- border: 1px solid rgba(99, 102, 241, 0.2);
90
- padding: 3rem 2rem;
91
- margin: 2rem 0;
92
- text-align: center;
93
- box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3);
94
- }
95
-
96
- .hero-subtitle {
97
- font-size: 1.3rem;
98
- color: #cbd5e1;
99
- max-width: 800px;
100
- margin: 0 auto 2rem auto;
101
- line-height: 1.6;
102
  }
103
-
104
  .metrics-container {
105
- display: flex;
106
- justify-content: center;
107
- gap: 2rem;
108
- margin: 2rem 0;
109
- flex-wrap: wrap;
110
  }
111
-
112
  .metric-card {
113
- background: rgba(42, 42, 84, 0.4);
114
- backdrop-filter: blur(10px);
115
- padding: 1.5rem;
116
- border-radius: 16px;
117
- border: 1px solid rgba(99, 102, 241, 0.2);
118
- text-align: center;
119
- transition: all 0.3s ease;
120
- min-width: 120px;
121
  }
122
-
123
- .metric-card:hover {
124
- transform: translateY(-5px);
125
- border-color: rgba(99, 102, 241, 0.5);
126
- box-shadow: 0 20px 25px rgba(99, 102, 241, 0.2);
127
- }
128
-
129
  .metric-value {
130
- font-size: 2.5rem;
131
- font-weight: 800;
132
- background: linear-gradient(135deg, #6366f1, #0ea5e9);
133
- -webkit-background-clip: text;
134
- -webkit-text-fill-color: transparent;
135
- display: block;
136
- margin-bottom: 0.5rem;
137
  }
138
-
139
- .metric-label {
140
- font-size: 0.875rem;
141
- color: #94a3b8;
142
- text-transform: uppercase;
143
- letter-spacing: 0.1em;
144
- font-weight: 600;
145
- }
146
-
147
- .verdict-container {
148
- padding: 2rem;
149
- border-radius: 20px;
150
- margin: 1rem 0;
151
- text-align: center;
152
- position: relative;
153
- overflow: hidden;
154
- }
155
-
156
- .verdict-fake {
157
- background: linear-gradient(135deg, #dc2626, #991b1b);
158
- box-shadow: 0 0 40px rgba(220, 38, 38, 0.3);
159
- animation: pulse-red 2s infinite;
160
- }
161
-
162
- .verdict-real {
163
- background: linear-gradient(135deg, #059669, #047857);
164
- box-shadow: 0 0 40px rgba(5, 150, 105, 0.3);
165
- animation: pulse-green 2s infinite;
166
- }
167
-
168
- @keyframes pulse-red {
169
- 0%, 100% { box-shadow: 0 0 40px rgba(220, 38, 38, 0.3); }
170
- 50% { box-shadow: 0 0 60px rgba(220, 38, 38, 0.5); }
171
- }
172
-
173
- @keyframes pulse-green {
174
- 0%, 100% { box-shadow: 0 0 40px rgba(5, 150, 105, 0.3); }
175
- 50% { box-shadow: 0 0 60px rgba(5, 150, 105, 0.5); }
176
- }
177
-
178
  .verdict-text {
179
- font-size: 3rem;
180
- font-weight: 800;
181
- color: white;
182
- text-shadow: 2px 2px 8px rgba(0,0,0,0.5);
183
- letter-spacing: 0.1em;
184
  }
185
-
186
- .glass-card {
187
- background: rgba(42, 42, 84, 0.4);
188
- backdrop-filter: blur(10px);
189
- border-radius: 16px;
190
- border: 1px solid rgba(99, 102, 241, 0.2);
191
- padding: 1.5rem;
192
- margin: 1rem 0;
193
- transition: all 0.3s ease;
194
- }
195
-
196
- .glass-card:hover {
197
- transform: translateY(-2px);
198
- border-color: rgba(99, 102, 241, 0.4);
199
- box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
200
  }
201
-
202
- .summary-box {
203
- background: rgba(99, 102, 241, 0.1);
204
- border-left: 5px solid #6366f1;
205
- padding: 1.5rem;
206
- border-radius: 8px;
207
- margin: 1rem 0;
208
- color: #f1f5f9;
209
  font-size: 1.1rem;
210
- line-height: 1.7;
211
- }
212
-
213
- .progress-container {
214
- margin: 1rem 0;
215
- }
216
-
217
- .progress-label {
218
- display: flex;
219
- justify-content: space-between;
220
- margin-bottom: 0.5rem;
221
- font-weight: 600;
222
- color: #f1f5f9;
223
  }
224
-
225
- .progress-bar-bg {
226
- background: rgba(42, 42, 84, 0.8);
227
- border-radius: 12px;
228
- height: 12px;
229
- overflow: hidden;
230
- position: relative;
231
- }
232
-
233
- .progress-bar-fill {
234
- height: 100%;
235
- background: linear-gradient(90deg, #6366f1, #0ea5e9);
236
- border-radius: 12px;
237
- transition: width 1s ease;
238
- position: relative;
239
- overflow: hidden;
240
- }
241
-
242
- .progress-bar-fill::after {
243
- content: '';
244
- position: absolute;
245
- top: 0;
246
- left: -100%;
247
- width: 100%;
248
- height: 100%;
249
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
250
- animation: shimmer 2s infinite;
251
- }
252
-
253
- @keyframes shimmer {
254
- 0% { left: -100%; }
255
- 100% { left: 100%; }
256
- }
257
-
258
- .stTextInput input, .stTextArea textarea {
259
- background: rgba(42, 42, 84, 0.6) !important;
260
- border: 2px solid rgba(99, 102, 241, 0.3) !important;
261
- border-radius: 16px !important;
262
- color: #f1f5f9 !important;
263
- font-size: 1.1rem !important;
264
- padding: 1rem !important;
265
- backdrop-filter: blur(10px) !important;
266
- transition: all 0.3s ease !important;
267
- }
268
-
269
- .stTextInput input:focus, .stTextArea textarea:focus {
270
- border-color: #6366f1 !important;
271
- box-shadow: 0 0 20px rgba(99, 102, 241, 0.3) !important;
272
- transform: translateY(-2px) !important;
273
- }
274
-
275
- .stButton button {
276
- background: linear-gradient(135deg, #6366f1, #4f46e5) !important;
277
- color: white !important;
278
- border: none !important;
279
- border-radius: 12px !important;
280
- font-weight: 600 !important;
281
- font-size: 1rem !important;
282
- padding: 0.75rem 2rem !important;
283
- transition: all 0.3s ease !important;
284
- text-transform: uppercase !important;
285
- letter-spacing: 0.05em !important;
286
- }
287
-
288
- .stButton button:hover {
289
- transform: translateY(-2px) !important;
290
- box-shadow: 0 10px 25px rgba(99, 102, 241, 0.3) !important;
291
- background: linear-gradient(135deg, #4f46e5, #6366f1) !important;
292
- }
293
-
294
- [data-testid="stSidebar"] {
295
- background: #161b22 !important;
296
- border-right: 1px solid rgba(99, 102, 241, 0.2) !important;
297
- }
298
-
299
- .footer-enhanced {
300
- text-align: center;
301
- padding: 2rem;
302
- margin-top: 3rem;
303
- background: rgba(42, 42, 84, 0.3);
304
- border-radius: 16px;
305
- border: 1px solid rgba(99, 102, 241, 0.2);
306
- color: #94a3b8;
307
- }
308
-
309
  .footer-features {
310
- display: flex;
311
- justify-content: center;
312
- align-items: center;
313
- gap: 2rem;
314
- margin-bottom: 1rem;
315
- flex-wrap: wrap;
316
- }
317
-
318
- .footer-feature {
319
- text-align: center;
320
  }
321
-
322
- .footer-feature-icon {
323
- font-size: 1.5rem;
324
- margin-bottom: 0.5rem;
325
- }
326
-
327
- .footer-feature-text {
328
- font-size: 0.8rem;
329
- color: #94a3b8;
330
- }
331
-
332
- @media (max-width: 768px) {
333
- .hero-container {
334
- padding: 2rem 1rem;
335
- border-radius: 16px;
336
- }
337
-
338
- .metrics-container {
339
- gap: 1rem;
340
- }
341
-
342
- .metric-card {
343
- min-width: 100px;
344
- padding: 1rem;
345
- }
346
-
347
- .metric-value {
348
- font-size: 2rem;
349
- }
350
-
351
- .verdict-text {
352
- font-size: 2rem;
353
- }
354
-
355
- .main-title {
356
- font-size: 2.5rem !important;
357
- }
358
-
359
- .hero-subtitle {
360
- font-size: 1.1rem;
361
- }
362
-
363
- .footer-features {
364
- gap: 1rem;
365
- }
366
- }
367
-
368
- @media (prefers-reduced-motion: reduce) {
369
- * {
370
- animation-duration: 0.01ms !important;
371
- animation-iteration-count: 1 !important;
372
- transition-duration: 0.01ms !important;
373
- }
374
- }
375
-
376
- *:focus {
377
- outline: 2px solid #6366f1 !important;
378
- outline-offset: 2px !important;
379
- }
380
- </style>
381
- """
382
-
383
- st.markdown(css_content, unsafe_allow_html=True)
384
-
385
- # Load CSS
386
- load_custom_css()
387
 
388
  # ==============================================================================
389
- # 🧠 AI MODEL SYSTEM
390
  # ==============================================================================
391
  BRAIN_1_MODEL = "Arko007/fact-check-v1"
392
  BRAIN_2_MODEL = "Arko007/fact-check1-v3-final"
393
 
394
  @st.cache_resource(show_spinner=False)
395
  def load_ai_models():
396
- """Load and cache AI models with enhanced error handling"""
397
  try:
398
- with st.spinner("πŸ”§ Loading AI models..."):
399
- # Load models with CPU device and custom cache
 
400
  classifier_b1 = pipeline(
401
  "text-classification",
402
  model=BRAIN_1_MODEL,
403
  return_all_scores=True,
404
  device=-1,
405
- cache_dir=temp_dir,
406
  model_kwargs={"torch_dtype": torch.float32}
407
  )
 
 
408
  classifier_b2 = pipeline(
409
  "text-classification",
410
  model=BRAIN_2_MODEL,
411
  device=-1,
412
- cache_dir=temp_dir,
413
  model_kwargs={"torch_dtype": torch.float32}
414
  )
415
- return classifier_b1, classifier_b2
 
 
416
 
417
  except Exception as e:
418
  st.error(f"πŸ”΄ Model loading failed: {str(e)}")
419
  return None, None
420
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  @st.cache_data(show_spinner=False, ttl=300)
422
  def fetch_web_content(url):
423
- """Enhanced web scraping with error handling"""
424
  try:
425
  headers = {
426
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
427
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
428
- 'Accept-Language': 'en-US,en;q=0.5',
429
- 'Accept-Encoding': 'gzip, deflate',
430
- 'Connection': 'keep-alive',
431
  }
432
-
433
  response = requests.get(url, headers=headers, timeout=15)
434
  response.raise_for_status()
435
 
436
  soup = BeautifulSoup(response.content, 'html.parser')
437
-
438
  # Remove unwanted elements
439
- for element in soup(['script', 'style', 'nav', 'footer', 'aside', 'header']):
440
  element.decompose()
441
 
442
- # Extract title
443
- title_element = soup.find('title')
444
- if not title_element:
445
- title_element = soup.find('h1')
446
- title = title_element.get_text(strip=True) if title_element else "No title found"
447
 
448
- # Extract content with multiple strategies
449
- content = ""
450
-
451
- # Strategy 1: Look for article content
452
- content_selectors = [
453
- 'article', 'main', '[role="main"]',
454
- '.content', '.article-body', '.post-content',
455
- '.entry-content', '.article-content'
456
- ]
457
 
458
- for selector in content_selectors:
459
- content_element = soup.select_one(selector)
460
- if content_element:
461
- content = content_element.get_text(separator=' ', strip=True)
462
- break
463
-
464
- # Strategy 2: Fall back to paragraphs
465
- if not content or len(content) < 100:
466
- paragraphs = soup.find_all('p')
467
- content = " ".join([p.get_text(strip=True) for p in paragraphs
468
- if len(p.get_text(strip=True)) > 20])
469
-
470
- # Clean and format text
471
- content = re.sub(r'\s+', ' ', content)
472
- content = re.sub(r'\n+', '\n', content)
473
- full_text = f"{title}\n\n{content}".strip()
474
 
475
  return {
476
  'success': True,
@@ -481,52 +405,31 @@ def fetch_web_content(url):
481
  'url': url
482
  }
483
 
484
- except requests.RequestException as e:
485
- return {'success': False, 'error': f'Network error: {str(e)}'}
486
  except Exception as e:
487
- return {'success': False, 'error': f'Processing error: {str(e)}'}
488
-
489
- def get_ai_summary(text_data, brain_1_results, brain_2_result, url=None):
490
- """Generate AI summary using Gemini"""
491
- try:
492
- if not API_CONFIGURED or not GENAI_AVAILABLE:
493
- # Fallback summary without AI
494
- b1_top = sorted(brain_1_results, key=lambda x: x['score'], reverse=True)[0]
495
- return f"Analysis complete: {brain_2_result['label']} verdict with {brain_2_result['score']:.1%} confidence. Primary nuance detected: {b1_top['label'].replace('-', ' ').title()} ({b1_top['score']:.1%})."
496
-
497
- b1_top = sorted(brain_1_results, key=lambda x: x['score'], reverse=True)[0]
498
 
499
- context = f"URL analysis: {url}" if url else "Direct text analysis"
500
- word_count = len(text_data.split()) if isinstance(text_data, str) else 0
501
-
502
- system_prompt = """You are Credo AI, an expert misinformation analyst. Provide clear, professional insights that help users understand information verification."""
503
-
504
- user_prompt = f"""
505
- Analysis Context: {context}
506
- Text Length: {word_count} words
507
- Content Preview: "{str(text_data)[:500]}..."
508
-
509
- AI Results:
510
- β€’ Verdict: {brain_2_result['label']} (Confidence: {brain_2_result['score']:.1%})
511
- β€’ Nuance: {b1_top['label'].replace('-', ' ').title()} ({b1_top['score']:.1%})
512
-
513
- Provide a clear 2-3 sentence summary explaining what these results mean and why the AI reached this conclusion.
514
- """
515
-
516
- model = genai.GenerativeModel(model_name="gemini-2.0-flash")
517
- response = model.generate_content([system_prompt, user_prompt])
518
- return response.text
519
-
520
- except Exception as e:
521
- # Fallback to basic summary
522
- b1_top = sorted(brain_1_results, key=lambda x: x['score'], reverse=True)[0]
523
- return f"Analysis complete: {brain_2_result['label']} verdict with {brain_2_result['score']:.1%} confidence. Primary nuance: {b1_top['label'].replace('-', ' ').title()}."
524
 
525
  # ==============================================================================
526
  # 🎨 UI COMPONENTS - FIXED HTML RENDERING
527
  # ==============================================================================
528
  def render_hero_section():
529
- """Render the hero section"""
530
  st.markdown("""
531
  <div class="hero-container">
532
  <h1 class="main-title">🧠 Credo AI Platform</h1>
@@ -534,7 +437,6 @@ def render_hero_section():
534
  Next-generation misinformation detection powered by <strong>dual-AI architecture</strong>.
535
  Analyze text, articles, and claims with unprecedented accuracy and insight.
536
  </p>
537
-
538
  <div class="metrics-container">
539
  <div class="metric-card">
540
  <span class="metric-value">99.9%</span>
@@ -553,10 +455,10 @@ def render_hero_section():
553
  """, unsafe_allow_html=True)
554
 
555
  def render_analysis_results(results):
556
- """Render analysis results with enhanced styling"""
557
  # AI Summary
558
  st.markdown("### ✨ AI-Powered Analysis Summary")
559
-
560
  st.markdown(f"""
561
  <div class="summary-box">
562
  {results['summary']}
@@ -568,8 +470,8 @@ def render_analysis_results(results):
568
 
569
  with col1:
570
  st.markdown("### 🎯 Primary Verdict")
571
- verdict = results['b2_label']
572
- confidence = results['b2_score']
573
 
574
  verdict_class = 'verdict-fake' if verdict == 'FAKE' else 'verdict-real'
575
 
@@ -583,213 +485,142 @@ def render_analysis_results(results):
583
  """, unsafe_allow_html=True)
584
 
585
  with col2:
586
- st.markdown("### 🧠 Nuance Analysis")
587
-
588
- progress_html = '<div class="glass-card">'
589
-
590
- for _, row in results['b1_df'].iterrows():
591
- label = row['label'].replace('-', ' ').title()
592
- score = row['score']
593
-
594
- progress_html += f"""
595
- <div class="progress-container">
596
- <div class="progress-label">
597
- <span>{label}</span>
598
- <span>{score:.1%}</span>
599
- </div>
600
- <div class="progress-bar-bg">
601
- <div class="progress-bar-fill" style="width: {score*100}%;"></div>
602
- </div>
603
- </div>
604
- """
605
-
606
- progress_html += '</div>'
607
-
608
- st.markdown(progress_html, unsafe_allow_html=True)
609
-
610
- # Analysis metadata
611
- if 'metadata' in results:
612
- metadata = results['metadata']
613
  st.markdown("### πŸ“Š Analysis Details")
614
-
615
- detail_cols = st.columns(4)
616
- with detail_cols[0]:
617
- st.metric("Word Count", metadata.get('word_count', 0))
618
- with detail_cols[1]:
619
- st.metric("Source Type", metadata.get('source_type', 'Text'))
620
- with detail_cols[2]:
621
- st.metric("Analysis Time", f"{metadata.get('analysis_time', 0):.2f}s")
622
- with detail_cols[3]:
623
- timestamp = results.get('timestamp', '')
624
- if timestamp:
625
- formatted_time = datetime.fromisoformat(timestamp.replace('Z', '+00:00')).strftime('%H:%M:%S')
626
- st.metric("Time", formatted_time)
627
 
628
  # ==============================================================================
629
- # 🎯 MAIN APPLICATION LOGIC
630
  # ==============================================================================
631
  def process_analysis(user_input, input_method):
632
- """Process analysis with comprehensive error handling"""
633
  start_time = time.time()
634
-
635
  with st.status("🧠 Analyzing with dual-AI system...", expanded=True) as status:
636
- st.write("πŸ”§ Loading AI models...")
637
- classifier_b1, classifier_b2 = load_ai_models()
638
-
639
- if not classifier_b1 or not classifier_b2:
640
- st.error("πŸ”΄ Failed to load AI models. Please try again or check your internet connection.")
641
- return
642
-
643
- text_to_analyze = user_input
644
- metadata = {
645
- 'source_type': input_method,
646
- 'timestamp': datetime.now().isoformat(),
647
- 'word_count': 0,
648
- 'analysis_time': 0
649
- }
650
-
651
  # Handle URL input
652
  if input_method == "URL/Website" and user_input.startswith(('http://', 'https://')):
653
  st.write("🌐 Fetching content from URL...")
654
  web_data = fetch_web_content(user_input)
655
-
656
  if web_data['success']:
657
  text_to_analyze = web_data['full_text']
658
- metadata.update({
659
- 'title': web_data.get('title', ''),
660
- 'word_count': web_data.get('word_count', 0),
661
- 'url': web_data.get('url', '')
662
- })
663
- st.write(f"βœ… Successfully extracted {metadata['word_count']} words")
664
-
665
- if metadata['word_count'] < 50:
666
- st.warning("⚠️ Very short content extracted. Results may be less reliable.")
667
  else:
668
  st.error(f"❌ Failed to fetch content: {web_data['error']}")
669
  return
670
  else:
671
- metadata['word_count'] = len(text_to_analyze.split())
672
-
673
- # Truncate text if too long for model processing
674
- max_length = 4000 # Safe limit for most models
675
- if len(text_to_analyze) > max_length:
676
- text_to_analyze = text_to_analyze[:max_length]
677
- st.write(f"βœ‚οΈ Text truncated to {max_length} characters for optimal processing")
678
 
679
- # Validate minimum content
680
- if len(text_to_analyze.strip()) < 10:
681
- st.warning("⚠️ Content too short for meaningful analysis. Please provide more text.")
682
- return
683
 
684
- # AI Analysis
685
- try:
 
 
 
 
686
  st.write("🧠 Brain 1: Performing nuance analysis...")
687
- brain_1_results = classifier_b1(text_to_analyze)
688
- if isinstance(brain_1_results, list) and len(brain_1_results) > 0:
689
- brain_1_results = brain_1_results[0]
690
-
691
- st.write("🎯 Brain 2: Generating specialist verdict...")
692
- brain_2_result = classifier_b2(text_to_analyze)
693
- if isinstance(brain_2_result, list) and len(brain_2_result) > 0:
694
- brain_2_result = brain_2_result[0]
695
-
696
- st.write("✨ Creating intelligent summary...")
697
- ai_summary = get_ai_summary(text_to_analyze, brain_1_results, brain_2_result,
698
- metadata.get('url') if input_method == "URL/Website" else None)
699
-
700
- metadata['analysis_time'] = time.time() - start_time
701
- status.update(label="βœ… Analysis complete!", state="complete")
702
-
703
- except Exception as e:
704
- st.error(f"❌ Analysis failed: {str(e)}")
705
- return
706
-
707
- # Store results
 
 
 
 
 
 
 
708
  results = {
 
 
 
 
709
  'input': user_input[:200] + "..." if len(user_input) > 200 else user_input,
710
- 'full_input': user_input,
711
- 'summary': ai_summary,
712
- 'b2_label': brain_2_result['label'],
713
- 'b2_score': brain_2_result['score'],
714
- 'b1_df': pd.DataFrame(brain_1_results).sort_values(by='score', ascending=False),
715
- 'metadata': metadata,
716
- 'timestamp': datetime.now().isoformat()
717
  }
718
-
719
  st.session_state.current_results = results
720
  st.session_state.analysis_complete = True
721
-
722
  # Add to history
723
  if 'analysis_history' not in st.session_state:
724
  st.session_state.analysis_history = []
725
-
726
- # Add to beginning of history
727
  st.session_state.analysis_history.insert(0, results)
728
-
729
- # Keep only latest 15 analyses to manage memory
730
- if len(st.session_state.analysis_history) > 15:
731
- st.session_state.analysis_history = st.session_state.analysis_history[:15]
732
-
733
  st.rerun()
734
 
735
  def render_analysis_interface():
736
- """Render the main analysis interface"""
737
  st.markdown("### πŸ” Content Analysis")
738
-
739
  # Input method selection
740
  input_method = st.selectbox(
741
  "Select input method:",
742
  ["Direct Text", "URL/Website", "File Upload"],
743
  help="Choose how you want to provide content for fact-checking"
744
  )
745
-
746
  user_input = ""
747
-
748
  if input_method == "Direct Text":
749
  user_input = st.text_area(
750
  "Enter text to analyze:",
751
  height=150,
752
  placeholder="Paste the content you want to fact-check here...",
753
- help="Enter any text content for misinformation detection",
754
- max_chars=5000
755
  )
756
-
757
  elif input_method == "URL/Website":
758
  user_input = st.text_input(
759
  "Enter website URL:",
760
  placeholder="https://example.com/article",
761
  help="Provide the URL of an article or webpage to analyze"
762
  )
763
-
764
  if user_input and not user_input.startswith(('http://', 'https://')):
765
  st.warning("⚠️ Please enter a complete URL starting with http:// or https://")
766
-
767
  elif input_method == "File Upload":
768
  uploaded_file = st.file_uploader(
769
  "Upload text file:",
770
- type=['txt', 'md', 'rtf'],
771
  help="Upload a text file containing the content to analyze"
772
  )
773
  if uploaded_file:
774
  try:
775
  user_input = str(uploaded_file.read(), "utf-8")
776
  st.success(f"βœ… File loaded: {len(user_input)} characters")
777
-
778
- # Show preview
779
  if len(user_input) > 500:
780
  st.text_area("Content preview:", user_input[:500] + "...", height=100, disabled=True)
781
- else:
782
- st.text_area("File content:", user_input, height=100, disabled=True)
783
-
784
  except Exception as e:
785
  st.error(f"❌ Error reading file: {str(e)}")
786
  user_input = ""
787
-
788
  # Analysis controls
789
  st.markdown("---")
790
 
791
  col1, col2, col3 = st.columns([3, 1, 1])
792
-
793
  with col1:
794
  analyze_btn = st.button(
795
  "🧠 Analyze with Dual-AI",
@@ -797,20 +628,20 @@ def render_analysis_interface():
797
  disabled=not user_input.strip(),
798
  help="Start the AI-powered fact-checking analysis"
799
  )
800
-
801
  with col2:
802
  if st.button("πŸ”„ Clear", help="Clear current results and start over"):
803
  st.session_state.analysis_complete = False
804
  st.session_state.current_results = {}
805
  st.rerun()
806
-
807
  with col3:
808
  export_enabled = st.session_state.get('analysis_complete', False)
809
- if st.button("πŸ“„ Export", disabled=not export_enabled, help="Export analysis results as JSON"):
810
  if export_enabled:
811
  export_results()
812
-
813
- # Input validation and processing
814
  if analyze_btn:
815
  if not user_input.strip():
816
  st.warning("⚠️ Please provide some content to analyze.")
@@ -822,168 +653,131 @@ def render_analysis_interface():
822
  process_analysis(user_input, input_method)
823
 
824
  def export_results():
825
- """Export analysis results as JSON"""
826
  if not st.session_state.get('current_results'):
827
  st.warning("⚠️ No results to export!")
828
  return
829
 
830
  results = st.session_state.current_results
831
-
832
- # Prepare export data
833
  export_data = {
834
- 'analysis_timestamp': results.get('timestamp', ''),
835
- 'input_method': results['metadata'].get('source_type', 'Unknown'),
836
  'input_text': results.get('full_input', results.get('input', '')),
837
- 'primary_verdict': results.get('b2_label', ''),
838
- 'confidence_score': float(results.get('b2_score', 0)),
839
  'ai_summary': results.get('summary', ''),
840
- 'nuance_analysis': [
841
- {
842
- 'category': row['label'].replace('-', ' ').title(),
843
- 'confidence': float(row['score'])
844
- }
845
- for _, row in results['b1_df'].iterrows()
846
- ],
847
- 'metadata': results.get('metadata', {}),
848
- 'export_timestamp': datetime.now().isoformat()
849
  }
850
 
851
  json_string = json.dumps(export_data, indent=2, default=str, ensure_ascii=False)
852
 
853
- # Create download button
854
  st.download_button(
855
  label="πŸ“₯ Download Analysis Report",
856
  data=json_string,
857
  file_name=f"credo_ai_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
858
  mime="application/json"
859
  )
860
-
861
  st.success("πŸ“„ Analysis report ready for download!")
862
 
863
  # ==============================================================================
864
- # 🎯 PAGE RENDERERS - FIXED NOTIFICATIONS
865
  # ==============================================================================
866
- def render_live_analysis_page():
867
- """Main analysis page"""
868
- render_hero_section()
869
 
870
- # Initialize session state
871
- if 'analysis_complete' not in st.session_state:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
872
  st.session_state.analysis_complete = False
873
- if 'current_results' not in st.session_state:
874
  st.session_state.current_results = {}
 
 
 
875
 
876
- # Show API status
 
 
 
877
  if not API_CONFIGURED:
878
- st.warning("πŸ”‘ **Setup Required:** Add your Google API key in Space Settings β†’ Variables and Secrets β†’ Add: GOOGLE_API_KEY. The platform will work with basic summaries until the API key is configured.")
879
-
880
- # Analysis interface
881
  render_analysis_interface()
882
-
883
  # Display results
884
  if st.session_state.analysis_complete and st.session_state.current_results:
885
  st.markdown("---")
886
  st.markdown("## πŸ“Š Analysis Results")
887
  render_analysis_results(st.session_state.current_results)
888
 
889
- def render_history_page():
890
- """Analysis history page"""
891
  st.markdown("# πŸ“œ Analysis History")
892
-
893
- if 'analysis_history' not in st.session_state or not st.session_state.analysis_history:
894
- st.info("πŸ“š **No Analysis History** - Your analysis history will appear here after you perform some fact-checking analyses. Start by going to the Live Analysis page and analyzing some content!")
895
- return
896
-
897
- history = st.session_state.analysis_history
898
-
899
- # Summary stats
900
- st.markdown("### πŸ“ˆ Summary Statistics")
901
- total = len(history)
902
- fake_count = sum(1 for h in history if h.get('b2_label') == 'FAKE')
903
- real_count = total - fake_count
904
 
905
- stat_cols = st.columns(4)
906
- with stat_cols[0]:
907
- st.metric("Total Analyses", total)
908
- with stat_cols[1]:
909
- st.metric("Fake Content", fake_count)
910
- with stat_cols[2]:
911
- st.metric("Real Content", real_count)
912
- with stat_cols[3]:
913
- st.metric("Fake Rate", f"{(fake_count/total*100):.1f}%" if total > 0 else "0%")
914
-
915
- # Filter controls
916
- st.markdown("### πŸ” Filter & Search")
917
- filter_cols = st.columns([2, 1, 1])
918
-
919
- with filter_cols[0]:
920
- search_term = st.text_input(
921
- "πŸ” Search in analysis history:",
922
- placeholder="Enter keywords to search...",
923
- help="Search through your analysis history"
924
- )
925
-
926
- with filter_cols[1]:
927
- verdict_filter = st.selectbox(
928
- "Filter by verdict:",
929
- ["All Results", "FAKE Only", "REAL Only"]
930
- )
931
-
932
- with filter_cols[2]:
933
- sort_order = st.selectbox(
934
- "Sort order:",
935
- ["Newest First", "Oldest First"]
936
- )
937
-
938
- # Apply filters
939
- filtered_history = history.copy()
940
-
941
- if search_term:
942
- search_lower = search_term.lower()
943
- filtered_history = [h for h in filtered_history
944
- if search_lower in str(h.get('input', '')).lower()
945
- or search_lower in str(h.get('summary', '')).lower()]
946
-
947
- if verdict_filter != "All Results":
948
- target_label = verdict_filter.split()[0] # "FAKE" or "REAL"
949
- filtered_history = [h for h in filtered_history
950
- if h.get('b2_label') == target_label]
951
-
952
- if sort_order == "Oldest First":
953
- filtered_history.reverse()
954
-
955
- # Display filtered results
956
- if filtered_history:
957
- st.info(f"πŸ“Š Showing {len(filtered_history)} of {len(history)} analyses")
958
-
959
- # Display history items
960
- for i, analysis in enumerate(filtered_history):
961
- # Create expandable item for each analysis
962
- original_index = len(history) - history.index(analysis)
963
- preview_text = analysis.get('input', 'No input')
964
- if len(preview_text) > 60:
965
- preview_text = preview_text[:60] + "..."
966
-
967
- timestamp_str = ""
968
- if 'timestamp' in analysis:
969
- try:
970
- dt = datetime.fromisoformat(analysis['timestamp'].replace('Z', '+00:00'))
971
- timestamp_str = dt.strftime('%m/%d %H:%M')
972
- except:
973
- timestamp_str = "Unknown time"
974
-
975
- with st.expander(
976
- f"**#{original_index}** {analysis.get('b2_label', 'Unknown')} | {preview_text} | {timestamp_str}",
977
- expanded=(i == 0) # Expand first item
978
- ):
979
- render_analysis_results(analysis)
980
  else:
981
- st.warning("πŸ” No analyses match your current filters.")
982
 
983
- def render_about_page():
984
- """About page with system information"""
985
  st.markdown("# πŸ”¬ About Credo AI")
986
-
987
  st.markdown("""
988
  <div class="glass-card">
989
  <h2 style="color: #6366f1; margin-bottom: 1rem;">πŸš€ Revolutionary Detection Technology</h2>
@@ -994,177 +788,69 @@ def render_about_page():
994
  </p>
995
  </div>
996
  """, unsafe_allow_html=True)
997
-
998
- # Technical details in tabs
999
- tab1, tab2, tab3, tab4 = st.tabs(["🧠 AI Architecture", "πŸ“Š Performance", "πŸ”¬ Technology", "πŸ› οΈ System Status"])
1000
-
1001
  with tab1:
1002
  st.markdown("""
1003
  ### ⚑ Brain 2: The Specialist
1004
  - **Model:** `Arko007/fact-check1-v3-final`
1005
- - **Primary Function:** Rapid FAKE/REAL binary classification
1006
- - **Training Data:** 80,000+ verified news articles
1007
- - **Performance:** 99.9% accuracy on test benchmarks
1008
  - **Speed:** Sub-second inference time
1009
-
1010
- ### 🧠 Brain 1: The Nuance Expert
1011
  - **Model:** `Arko007/fact-check-v1`
1012
- - **Primary Function:** Multi-class contextual analysis
1013
- - **Training Data:** LIAR dataset with political fact-checking
1014
  - **Specialization:** Detects subtle misinformation patterns
1015
  - **Capability:** Handles complex and ambiguous claims
1016
-
1017
- ### ✨ Gemini 2.0 Integration
1018
- - **Role:** Intelligent synthesis and explanation layer
1019
- - **Function:** Converts technical AI outputs into human-readable insights
1020
- - **Value:** Makes complex AI decisions accessible to all users
1021
- - **Fallback:** Provides basic summaries when API unavailable
1022
  """)
1023
-
1024
  with tab2:
1025
- st.markdown("#### πŸ“ˆ Benchmark Performance")
1026
 
1027
- # Performance metrics table
1028
  metrics_data = {
1029
- 'Metric': ['Accuracy', 'Precision', 'Recall', 'F1-Score', 'Processing Speed'],
1030
- 'Brain 1 (Nuance)': ['94.2%', '93.8%', '92.1%', '92.9%', '1.2s avg'],
1031
- 'Brain 2 (Binary)': ['99.9%', '99.8%', '99.7%', '99.7%', '0.8s avg'],
1032
- 'Combined System': ['99.2%', '99.1%', '98.9%', '99.0%', '2.1s avg']
1033
  }
1034
-
1035
- df = pd.DataFrame(metrics_data)
1036
- st.dataframe(df, use_container_width=True, hide_index=True)
1037
-
1038
  st.success("πŸ† **Industry Leading:** Credo AI consistently outperforms single-model approaches by 15-25% across major misinformation datasets.")
1039
-
1040
  with tab3:
1041
  st.markdown("""
1042
  ### πŸ› οΈ Technology Stack
1043
-
1044
  **πŸ€– Core AI/ML:**
1045
  - PyTorch deep learning framework
1046
  - Transformers library for model handling
1047
  - BERT-based language understanding
1048
  - Advanced fine-tuning techniques
1049
- - CPU-optimized inference pipeline
1050
-
1051
  **🌐 Web & Integration:**
1052
  - Streamlit for responsive UI
1053
- - Beautiful Soup for web scraping
1054
  - Google Generative AI (Gemini 2.0)
1055
- - Requests for HTTP handling
1056
  - Custom CSS for enhanced UX
1057
-
1058
- **⚑ Performance & Optimization:**
1059
  - Intelligent caching system
1060
  - Memory-efficient processing
1061
- - Progressive loading
1062
  - Mobile-responsive design
1063
-
1064
- **πŸ”’ Privacy & Security:**
1065
- - No persistent data storage
1066
- - Secure API key management
1067
  - Privacy-first architecture
1068
- - Local processing where possible
1069
  """)
1070
 
1071
- with tab4:
1072
- st.markdown("#### πŸ”§ Current System Status")
1073
-
1074
- # System status indicators
1075
- status_data = []
1076
-
1077
- # API Status
1078
- api_status = "🟒 Connected" if API_CONFIGURED else "🟑 Basic Mode"
1079
- status_data.append(["Google AI API", api_status])
1080
-
1081
- # Model availability
1082
- try:
1083
- load_ai_models()
1084
- model_status = "🟒 Ready"
1085
- except:
1086
- model_status = "πŸ”΄ Loading"
1087
- status_data.append(["AI Models", model_status])
1088
-
1089
- # Memory usage
1090
- if 'analysis_history' in st.session_state:
1091
- history_count = len(st.session_state.analysis_history)
1092
- memory_status = f"🟒 {history_count}/15 analyses"
1093
- else:
1094
- memory_status = "🟒 Clean"
1095
- status_data.append(["Memory Usage", memory_status])
1096
-
1097
- # Web scraping
1098
- web_status = "🟒 Available"
1099
- status_data.append(["Web Scraping", web_status])
1100
-
1101
- status_df = pd.DataFrame(status_data, columns=['Component', 'Status'])
1102
- st.dataframe(status_df, use_container_width=True, hide_index=True)
1103
-
1104
- # ==============================================================================
1105
- # 🌟 MAIN APPLICATION
1106
- # ==============================================================================
1107
-
1108
- # Initialize session state
1109
- if 'analysis_history' not in st.session_state:
1110
- st.session_state.analysis_history = []
1111
-
1112
- # Sidebar navigation
1113
- with st.sidebar:
1114
- # Sidebar header
1115
- st.markdown("""
1116
- <div style="text-align: center; padding: 1rem 0; margin-bottom: 2rem;">
1117
- <h2 style="color: #6366f1; margin: 0;">🧠 Credo AI</h2>
1118
- <p style="color: #94a3b8; margin: 0.5rem 0 0 0; font-size: 0.9rem;">Truth Detection Platform</p>
1119
- </div>
1120
- """, unsafe_allow_html=True)
1121
-
1122
- # Navigation
1123
- page = st.radio(
1124
- "Navigate:",
1125
- ["πŸš€ Live Analysis", "πŸ“œ History", "ℹ️ About"],
1126
- key="navigation"
1127
- )
1128
-
1129
- # Quick stats in sidebar
1130
- if st.session_state.analysis_history:
1131
- st.markdown("---")
1132
- st.markdown("### πŸ“ˆ Quick Stats")
1133
- total = len(st.session_state.analysis_history)
1134
- fake_count = sum(1 for h in st.session_state.analysis_history if h.get('b2_label') == 'FAKE')
1135
-
1136
- st.metric("Sessions", total)
1137
- if total > 0:
1138
- st.metric("Fake Rate", f"{(fake_count/total*100):.0f}%")
1139
-
1140
- # System status in sidebar
1141
- st.markdown("---")
1142
- st.markdown("### πŸ”§ Status")
1143
-
1144
- # API indicator
1145
- if API_CONFIGURED:
1146
- st.success("🟒 AI Enhanced")
1147
- else:
1148
- st.warning("🟑 Basic Mode")
1149
-
1150
- # Quick actions
1151
- st.markdown("---")
1152
- if st.button("πŸ—‘οΈ Clear History", help="Clear all analysis history"):
1153
- st.session_state.analysis_history = []
1154
- st.session_state.analysis_complete = False
1155
- st.session_state.current_results = {}
1156
- st.success("History cleared!")
1157
- time.sleep(1)
1158
- st.rerun()
1159
-
1160
- # Main content area
1161
- if page == "πŸš€ Live Analysis":
1162
- render_live_analysis_page()
1163
- elif page == "πŸ“œ History":
1164
- render_history_page()
1165
- elif page == "ℹ️ About":
1166
- render_about_page()
1167
-
1168
  # Footer
1169
  st.markdown("""
1170
  <div class="footer-enhanced">
@@ -1193,4 +879,4 @@ st.markdown("""
1193
  Powered by Advanced AI β€’ Making Truth Accessible to Everyone
1194
  </div>
1195
  </div>
1196
- """, unsafe_allow_html=True)
 
1
+ # Fix HuggingFace cache permissions
2
  import os
3
  import tempfile
4
+ import gc
5
 
6
+ # Set cache directories properly
7
+ os.environ['HF_HOME'] = '/tmp'
8
+ os.environ['TRANSFORMERS_CACHE'] = '/tmp'
9
+ os.environ['HF_HUB_CACHE'] = '/tmp'
 
10
 
11
  import streamlit as st
12
  import torch
 
46
  try:
47
  genai.configure(api_key=GOOGLE_API_KEY)
48
  API_CONFIGURED = True
49
+ except Exception:
50
  API_CONFIGURED = False
51
  else:
52
  API_CONFIGURED = False
53
 
54
  # ==============================================================================
55
+ # 🎨 ENHANCED CSS STYLING - FIXED
56
  # ==============================================================================
57
+ st.markdown("""
58
+ <style>
59
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
60
+
61
+ .stApp {
62
+ background: linear-gradient(135deg, #0f0f23 0%, #1a1a3a 100%);
63
+ color: #f1f5f9;
64
+ font-family: 'Inter', sans-serif;
65
+ }
66
+
67
+ .main-title {
68
+ font-size: clamp(2.5rem, 5vw, 4rem);
69
+ background: linear-gradient(135deg, #6366f1, #0ea5e9);
70
+ -webkit-background-clip: text;
71
+ -webkit-text-fill-color: transparent;
72
+ text-align: center;
73
+ margin: 2rem 0;
74
+ font-weight: 800;
75
+ animation: glow 3s ease-in-out infinite alternate;
76
+ }
77
+
78
+ @keyframes glow {
79
+ from { filter: drop-shadow(0 0 20px rgba(99, 102, 241, 0.3)); }
80
+ to { filter: drop-shadow(0 0 40px rgba(99, 102, 241, 0.6)); }
81
+ }
82
+
83
+ .hero-container {
84
+ background: rgba(42, 42, 84, 0.3);
85
+ backdrop-filter: blur(20px);
86
+ border-radius: 24px;
87
+ border: 1px solid rgba(99, 102, 241, 0.2);
88
+ padding: 3rem 2rem;
89
+ margin: 2rem 0;
90
+ text-align: center;
91
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3);
92
+ }
93
+
94
+ .hero-subtitle {
95
+ font-size: 1.3rem;
96
+ color: #cbd5e1;
97
+ max-width: 800px;
98
+ margin: 0 auto 2rem auto;
99
+ line-height: 1.6;
100
+ }
101
+
102
+ .metrics-container {
103
+ display: flex;
104
+ justify-content: center;
105
+ gap: 2rem;
106
+ margin: 2rem 0;
107
+ flex-wrap: wrap;
108
+ }
109
+
110
+ .metric-card {
111
+ background: rgba(42, 42, 84, 0.4);
112
+ backdrop-filter: blur(10px);
113
+ padding: 1.5rem;
114
+ border-radius: 16px;
115
+ border: 1px solid rgba(99, 102, 241, 0.2);
116
+ text-align: center;
117
+ transition: all 0.3s ease;
118
+ min-width: 120px;
119
+ }
120
+
121
+ .metric-card:hover {
122
+ transform: translateY(-5px);
123
+ border-color: rgba(99, 102, 241, 0.5);
124
+ box-shadow: 0 20px 25px rgba(99, 102, 241, 0.2);
125
+ }
126
+
127
+ .metric-value {
128
+ font-size: 2.5rem;
129
+ font-weight: 800;
130
+ background: linear-gradient(135deg, #6366f1, #0ea5e9);
131
+ -webkit-background-clip: text;
132
+ -webkit-text-fill-color: transparent;
133
+ display: block;
134
+ margin-bottom: 0.5rem;
135
+ }
136
+
137
+ .metric-label {
138
+ font-size: 0.875rem;
139
+ color: #94a3b8;
140
+ text-transform: uppercase;
141
+ letter-spacing: 0.1em;
142
+ font-weight: 600;
143
+ }
144
+
145
+ .verdict-container {
146
+ padding: 2rem;
147
+ border-radius: 20px;
148
+ margin: 1rem 0;
149
+ text-align: center;
150
+ position: relative;
151
+ overflow: hidden;
152
+ }
153
+
154
+ .verdict-fake {
155
+ background: linear-gradient(135deg, #dc2626, #991b1b);
156
+ box-shadow: 0 0 40px rgba(220, 38, 38, 0.3);
157
+ animation: pulse-red 2s infinite;
158
+ }
159
+
160
+ .verdict-real {
161
+ background: linear-gradient(135deg, #059669, #047857);
162
+ box-shadow: 0 0 40px rgba(5, 150, 105, 0.3);
163
+ animation: pulse-green 2s infinite;
164
+ }
165
+
166
+ @keyframes pulse-red {
167
+ 0%, 100% { box-shadow: 0 0 40px rgba(220, 38, 38, 0.3); }
168
+ 50% { box-shadow: 0 0 60px rgba(220, 38, 38, 0.5); }
169
+ }
170
+
171
+ @keyframes pulse-green {
172
+ 0%, 100% { box-shadow: 0 0 40px rgba(5, 150, 105, 0.3); }
173
+ 50% { box-shadow: 0 0 60px rgba(5, 150, 105, 0.5); }
174
+ }
175
+
176
+ .verdict-text {
177
+ font-size: 3rem;
178
+ font-weight: 800;
179
+ color: white;
180
+ text-shadow: 2px 2px 8px rgba(0,0,0,0.5);
181
+ letter-spacing: 0.1em;
182
+ }
183
+
184
+ .glass-card {
185
+ background: rgba(42, 42, 84, 0.4);
186
+ backdrop-filter: blur(10px);
187
+ border-radius: 16px;
188
+ border: 1px solid rgba(99, 102, 241, 0.2);
189
+ padding: 1.5rem;
190
+ margin: 1rem 0;
191
+ transition: all 0.3s ease;
192
+ }
193
+
194
+ .summary-box {
195
+ background: rgba(99, 102, 241, 0.1);
196
+ border-left: 5px solid #6366f1;
197
+ padding: 1.5rem;
198
+ border-radius: 8px;
199
+ margin: 1rem 0;
200
+ color: #f1f5f9;
201
+ font-size: 1.1rem;
202
+ line-height: 1.7;
203
+ }
204
+
205
+ .progress-container {
206
+ margin: 1rem 0;
207
+ }
208
+
209
+ .progress-label {
210
+ display: flex;
211
+ justify-content: space-between;
212
+ margin-bottom: 0.5rem;
213
+ font-weight: 600;
214
+ color: #f1f5f9;
215
+ }
216
+
217
+ .progress-bar-bg {
218
+ background: rgba(42, 42, 84, 0.8);
219
+ border-radius: 12px;
220
+ height: 12px;
221
+ overflow: hidden;
222
+ position: relative;
223
+ }
224
+
225
+ .progress-bar-fill {
226
+ height: 100%;
227
+ background: linear-gradient(90deg, #6366f1, #0ea5e9);
228
+ border-radius: 12px;
229
+ transition: width 1s ease;
230
+ }
231
+
232
+ .stTextInput input, .stTextArea textarea {
233
+ background: rgba(42, 42, 84, 0.6) !important;
234
+ border: 2px solid rgba(99, 102, 241, 0.3) !important;
235
+ border-radius: 16px !important;
236
+ color: #f1f5f9 !important;
237
+ font-size: 1.1rem !important;
238
+ padding: 1rem !important;
239
+ }
240
+
241
+ .stButton button {
242
+ background: linear-gradient(135deg, #6366f1, #4f46e5) !important;
243
+ color: white !important;
244
+ border: none !important;
245
+ border-radius: 12px !important;
246
+ font-weight: 600 !important;
247
+ font-size: 1rem !important;
248
+ padding: 0.75rem 2rem !important;
249
+ text-transform: uppercase !important;
250
+ }
251
+
252
+ [data-testid="stSidebar"] {
253
+ background: #161b22 !important;
254
+ border-right: 1px solid rgba(99, 102, 241, 0.2) !important;
255
+ }
256
+
257
+ .footer-enhanced {
258
+ text-align: center;
259
+ padding: 2rem;
260
+ margin-top: 3rem;
261
+ background: rgba(42, 42, 84, 0.3);
262
+ border-radius: 16px;
263
+ border: 1px solid rgba(99, 102, 241, 0.2);
264
+ color: #94a3b8;
265
+ }
266
+
267
+ .footer-features {
268
+ display: flex;
269
+ justify-content: center;
270
+ align-items: center;
271
+ gap: 2rem;
272
+ margin-bottom: 1rem;
273
+ flex-wrap: wrap;
274
+ }
275
+
276
+ .footer-feature {
277
+ text-align: center;
278
+ }
279
+
280
+ .footer-feature-icon {
281
+ font-size: 1.5rem;
282
+ margin-bottom: 0.5rem;
283
+ }
284
+
285
+ .footer-feature-text {
286
+ font-size: 0.8rem;
287
+ color: #94a3b8;
288
+ }
289
+
290
+ @media (max-width: 768px) {
291
  .hero-container {
292
+ padding: 2rem 1rem;
293
+ border-radius: 16px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  }
 
295
  .metrics-container {
296
+ gap: 1rem;
 
 
 
 
297
  }
 
298
  .metric-card {
299
+ min-width: 100px;
300
+ padding: 1rem;
 
 
 
 
 
 
301
  }
 
 
 
 
 
 
 
302
  .metric-value {
303
+ font-size: 2rem;
 
 
 
 
 
 
304
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  .verdict-text {
306
+ font-size: 2rem;
 
 
 
 
307
  }
308
+ .main-title {
309
+ font-size: 2.5rem !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  }
311
+ .hero-subtitle {
 
 
 
 
 
 
 
312
  font-size: 1.1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
  .footer-features {
315
+ gap: 1rem;
 
 
 
 
 
 
 
 
 
316
  }
317
+ }
318
+ </style>
319
+ """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
 
321
  # ==============================================================================
322
+ # 🧠 AI MODEL SYSTEM - FIXED CACHE ERROR
323
  # ==============================================================================
324
  BRAIN_1_MODEL = "Arko007/fact-check-v1"
325
  BRAIN_2_MODEL = "Arko007/fact-check1-v3-final"
326
 
327
  @st.cache_resource(show_spinner=False)
328
  def load_ai_models():
329
+ """Load and cache AI models - FIXED VERSION"""
330
  try:
331
+ with st.status("πŸ”§ Loading AI models...", expanded=True) as status:
332
+ st.write("🧠 Initializing Brain 1...")
333
+ # Load without cache_dir parameter to avoid error
334
  classifier_b1 = pipeline(
335
  "text-classification",
336
  model=BRAIN_1_MODEL,
337
  return_all_scores=True,
338
  device=-1,
 
339
  model_kwargs={"torch_dtype": torch.float32}
340
  )
341
+
342
+ st.write("🎯 Initializing Brain 2...")
343
  classifier_b2 = pipeline(
344
  "text-classification",
345
  model=BRAIN_2_MODEL,
346
  device=-1,
 
347
  model_kwargs={"torch_dtype": torch.float32}
348
  )
349
+
350
+ status.update(label="βœ… AI models loaded successfully!", state="complete")
351
+ return classifier_b1, classifier_b2
352
 
353
  except Exception as e:
354
  st.error(f"πŸ”΄ Model loading failed: {str(e)}")
355
  return None, None
356
 
357
+ def get_fallback_analysis(text):
358
+ """Simple fallback analysis when models can't load"""
359
+ fake_indicators = ['fake', 'hoax', 'conspiracy', 'false', 'lie', 'scam', 'fraud', 'misleading']
360
+ real_indicators = ['study', 'research', 'according', 'official', 'confirmed', 'verified', 'report']
361
+
362
+ text_lower = text.lower()
363
+ fake_score = sum(1 for word in fake_indicators if word in text_lower)
364
+ real_score = sum(1 for word in real_indicators if word in text_lower)
365
+
366
+ if fake_score > real_score:
367
+ return "FAKE", 0.78, "This content contains several indicators commonly associated with misinformation."
368
+ elif real_score > fake_score:
369
+ return "REAL", 0.72, "This content contains indicators typically found in factual reporting."
370
+ else:
371
+ return "UNCERTAIN", 0.55, "This content shows mixed indicators and requires careful verification."
372
+
373
  @st.cache_data(show_spinner=False, ttl=300)
374
  def fetch_web_content(url):
375
+ """Enhanced web scraping"""
376
  try:
377
  headers = {
378
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
 
 
 
 
379
  }
 
380
  response = requests.get(url, headers=headers, timeout=15)
381
  response.raise_for_status()
382
 
383
  soup = BeautifulSoup(response.content, 'html.parser')
384
+
385
  # Remove unwanted elements
386
+ for element in soup(['script', 'style', 'nav', 'footer', 'aside']):
387
  element.decompose()
388
 
389
+ # Get title
390
+ title = soup.find('title')
391
+ title = title.get_text(strip=True) if title else "No title found"
 
 
392
 
393
+ # Get content
394
+ paragraphs = soup.find_all('p')
395
+ content = " ".join([p.get_text(strip=True) for p in paragraphs if len(p.get_text(strip=True)) > 20])
 
 
 
 
 
 
396
 
397
+ full_text = f"{title}\n\n{content}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
 
399
  return {
400
  'success': True,
 
405
  'url': url
406
  }
407
 
 
 
408
  except Exception as e:
409
+ return {'success': False, 'error': str(e)}
 
 
 
 
 
 
 
 
 
 
410
 
411
+ def get_ai_summary(text_data, verdict, confidence):
412
+ """Generate AI summary"""
413
+ if API_CONFIGURED and GENAI_AVAILABLE:
414
+ try:
415
+ prompt = f"""Analyze this {verdict} content (confidence: {confidence:.1%}).
416
+ Content: {text_data[:400]}...
417
+
418
+ Provide a brief 2-sentence professional summary explaining why this content was classified as {verdict}."""
419
+
420
+ model = genai.GenerativeModel(model_name="gemini-2.0-flash")
421
+ response = model.generate_content(prompt)
422
+ return response.text
423
+ except:
424
+ pass
425
+
426
+ return f"Analysis complete: {verdict} verdict with {confidence:.1%} confidence based on content analysis and pattern recognition."
 
 
 
 
 
 
 
 
 
427
 
428
  # ==============================================================================
429
  # 🎨 UI COMPONENTS - FIXED HTML RENDERING
430
  # ==============================================================================
431
  def render_hero_section():
432
+ """Render hero section - FIXED"""
433
  st.markdown("""
434
  <div class="hero-container">
435
  <h1 class="main-title">🧠 Credo AI Platform</h1>
 
437
  Next-generation misinformation detection powered by <strong>dual-AI architecture</strong>.
438
  Analyze text, articles, and claims with unprecedented accuracy and insight.
439
  </p>
 
440
  <div class="metrics-container">
441
  <div class="metric-card">
442
  <span class="metric-value">99.9%</span>
 
455
  """, unsafe_allow_html=True)
456
 
457
  def render_analysis_results(results):
458
+ """Render analysis results - FIXED"""
459
  # AI Summary
460
  st.markdown("### ✨ AI-Powered Analysis Summary")
461
+
462
  st.markdown(f"""
463
  <div class="summary-box">
464
  {results['summary']}
 
470
 
471
  with col1:
472
  st.markdown("### 🎯 Primary Verdict")
473
+ verdict = results['verdict']
474
+ confidence = results['confidence']
475
 
476
  verdict_class = 'verdict-fake' if verdict == 'FAKE' else 'verdict-real'
477
 
 
485
  """, unsafe_allow_html=True)
486
 
487
  with col2:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  st.markdown("### πŸ“Š Analysis Details")
489
+ st.metric("Processing Time", f"{results.get('analysis_time', 0):.2f}s")
490
+ st.metric("Content Length", f"{len(results.get('input', '').split())} words")
491
+ st.metric("Analysis Method", "AI Analysis" if verdict in ['FAKE', 'REAL'] else "Pattern Analysis")
 
 
 
 
 
 
 
 
 
 
492
 
493
  # ==============================================================================
494
+ # 🎯 MAIN APPLICATION LOGIC - FIXED
495
  # ==============================================================================
496
  def process_analysis(user_input, input_method):
497
+ """Process analysis - FIXED VERSION"""
498
  start_time = time.time()
499
+
500
  with st.status("🧠 Analyzing with dual-AI system...", expanded=True) as status:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501
  # Handle URL input
502
  if input_method == "URL/Website" and user_input.startswith(('http://', 'https://')):
503
  st.write("🌐 Fetching content from URL...")
504
  web_data = fetch_web_content(user_input)
 
505
  if web_data['success']:
506
  text_to_analyze = web_data['full_text']
507
+ st.write(f"βœ… Successfully extracted {web_data['word_count']} words")
 
 
 
 
 
 
 
 
508
  else:
509
  st.error(f"❌ Failed to fetch content: {web_data['error']}")
510
  return
511
  else:
512
+ text_to_analyze = user_input
 
 
 
 
 
 
513
 
514
+ # Truncate if too long
515
+ if len(text_to_analyze) > 3000:
516
+ text_to_analyze = text_to_analyze[:3000]
517
+ st.write("βœ‚οΈ Text truncated for optimal processing")
518
 
519
+ # Try to load models
520
+ st.write("πŸ”§ Loading AI models...")
521
+ classifier_b1, classifier_b2 = load_ai_models()
522
+
523
+ if classifier_b1 and classifier_b2:
524
+ # Use full AI analysis
525
  st.write("🧠 Brain 1: Performing nuance analysis...")
526
+ try:
527
+ brain_1_results = classifier_b1(text_to_analyze)
528
+ if isinstance(brain_1_results, list) and len(brain_1_results) > 0:
529
+ brain_1_results = brain_1_results[0]
530
+
531
+ st.write("🎯 Brain 2: Generating specialist verdict...")
532
+ brain_2_result = classifier_b2(text_to_analyze)
533
+ if isinstance(brain_2_result, list) and len(brain_2_result) > 0:
534
+ brain_2_result = brain_2_result[0]
535
+
536
+ verdict = brain_2_result['label']
537
+ confidence = brain_2_result['score']
538
+
539
+ st.write("✨ Creating intelligent summary...")
540
+ summary = get_ai_summary(text_to_analyze, verdict, confidence)
541
+
542
+ except Exception as e:
543
+ st.write("⚠️ AI analysis failed, using fallback analysis...")
544
+ verdict, confidence, summary = get_fallback_analysis(text_to_analyze)
545
+ else:
546
+ # Use fallback analysis
547
+ st.write("πŸ”„ Using pattern-based analysis...")
548
+ verdict, confidence, summary = get_fallback_analysis(text_to_analyze)
549
+
550
+ analysis_time = time.time() - start_time
551
+ status.update(label="βœ… Analysis complete!", state="complete")
552
+
553
+ # Store and display results
554
  results = {
555
+ 'verdict': verdict,
556
+ 'confidence': confidence,
557
+ 'summary': summary,
558
+ 'analysis_time': analysis_time,
559
  'input': user_input[:200] + "..." if len(user_input) > 200 else user_input,
560
+ 'full_input': user_input
 
 
 
 
 
 
561
  }
562
+
563
  st.session_state.current_results = results
564
  st.session_state.analysis_complete = True
565
+
566
  # Add to history
567
  if 'analysis_history' not in st.session_state:
568
  st.session_state.analysis_history = []
 
 
569
  st.session_state.analysis_history.insert(0, results)
570
+ if len(st.session_state.analysis_history) > 10:
571
+ st.session_state.analysis_history = st.session_state.analysis_history[:10]
572
+
 
 
573
  st.rerun()
574
 
575
  def render_analysis_interface():
576
+ """Main analysis interface - FIXED"""
577
  st.markdown("### πŸ” Content Analysis")
578
+
579
  # Input method selection
580
  input_method = st.selectbox(
581
  "Select input method:",
582
  ["Direct Text", "URL/Website", "File Upload"],
583
  help="Choose how you want to provide content for fact-checking"
584
  )
585
+
586
  user_input = ""
587
+
588
  if input_method == "Direct Text":
589
  user_input = st.text_area(
590
  "Enter text to analyze:",
591
  height=150,
592
  placeholder="Paste the content you want to fact-check here...",
593
+ help="Enter any text content for misinformation detection"
 
594
  )
 
595
  elif input_method == "URL/Website":
596
  user_input = st.text_input(
597
  "Enter website URL:",
598
  placeholder="https://example.com/article",
599
  help="Provide the URL of an article or webpage to analyze"
600
  )
 
601
  if user_input and not user_input.startswith(('http://', 'https://')):
602
  st.warning("⚠️ Please enter a complete URL starting with http:// or https://")
 
603
  elif input_method == "File Upload":
604
  uploaded_file = st.file_uploader(
605
  "Upload text file:",
606
+ type=['txt', 'md'],
607
  help="Upload a text file containing the content to analyze"
608
  )
609
  if uploaded_file:
610
  try:
611
  user_input = str(uploaded_file.read(), "utf-8")
612
  st.success(f"βœ… File loaded: {len(user_input)} characters")
 
 
613
  if len(user_input) > 500:
614
  st.text_area("Content preview:", user_input[:500] + "...", height=100, disabled=True)
 
 
 
615
  except Exception as e:
616
  st.error(f"❌ Error reading file: {str(e)}")
617
  user_input = ""
618
+
619
  # Analysis controls
620
  st.markdown("---")
621
 
622
  col1, col2, col3 = st.columns([3, 1, 1])
623
+
624
  with col1:
625
  analyze_btn = st.button(
626
  "🧠 Analyze with Dual-AI",
 
628
  disabled=not user_input.strip(),
629
  help="Start the AI-powered fact-checking analysis"
630
  )
631
+
632
  with col2:
633
  if st.button("πŸ”„ Clear", help="Clear current results and start over"):
634
  st.session_state.analysis_complete = False
635
  st.session_state.current_results = {}
636
  st.rerun()
637
+
638
  with col3:
639
  export_enabled = st.session_state.get('analysis_complete', False)
640
+ if st.button("πŸ“„ Export", disabled=not export_enabled, help="Export analysis results"):
641
  if export_enabled:
642
  export_results()
643
+
644
+ # Process analysis
645
  if analyze_btn:
646
  if not user_input.strip():
647
  st.warning("⚠️ Please provide some content to analyze.")
 
653
  process_analysis(user_input, input_method)
654
 
655
  def export_results():
656
+ """Export analysis results"""
657
  if not st.session_state.get('current_results'):
658
  st.warning("⚠️ No results to export!")
659
  return
660
 
661
  results = st.session_state.current_results
 
 
662
  export_data = {
663
+ 'analysis_timestamp': datetime.now().isoformat(),
 
664
  'input_text': results.get('full_input', results.get('input', '')),
665
+ 'verdict': results.get('verdict', ''),
666
+ 'confidence_score': float(results.get('confidence', 0)),
667
  'ai_summary': results.get('summary', ''),
668
+ 'analysis_time': results.get('analysis_time', 0)
 
 
 
 
 
 
 
 
669
  }
670
 
671
  json_string = json.dumps(export_data, indent=2, default=str, ensure_ascii=False)
672
 
 
673
  st.download_button(
674
  label="πŸ“₯ Download Analysis Report",
675
  data=json_string,
676
  file_name=f"credo_ai_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
677
  mime="application/json"
678
  )
 
679
  st.success("πŸ“„ Analysis report ready for download!")
680
 
681
  # ==============================================================================
682
+ # 🌟 MAIN APPLICATION - FIXED PAGES
683
  # ==============================================================================
 
 
 
684
 
685
+ # Initialize session state
686
+ if 'analysis_complete' not in st.session_state:
687
+ st.session_state.analysis_complete = False
688
+ if 'current_results' not in st.session_state:
689
+ st.session_state.current_results = {}
690
+ if 'analysis_history' not in st.session_state:
691
+ st.session_state.analysis_history = []
692
+
693
+ # Sidebar
694
+ with st.sidebar:
695
+ st.markdown("""
696
+ <div style="text-align: center; padding: 1rem 0; margin-bottom: 2rem;">
697
+ <h2 style="color: #6366f1; margin: 0;">🧠 Credo AI</h2>
698
+ <p style="color: #94a3b8; margin: 0.5rem 0 0 0; font-size: 0.9rem;">Truth Detection Platform</p>
699
+ </div>
700
+ """, unsafe_allow_html=True)
701
+
702
+ page = st.radio(
703
+ "Navigate:",
704
+ ["πŸš€ Live Analysis", "πŸ“œ History", "ℹ️ About"],
705
+ key="navigation"
706
+ )
707
+
708
+ # Quick stats
709
+ if st.session_state.analysis_history:
710
+ st.markdown("---")
711
+ st.markdown("### πŸ“ˆ Quick Stats")
712
+ total = len(st.session_state.analysis_history)
713
+ fake_count = sum(1 for h in st.session_state.analysis_history if h.get('verdict') == 'FAKE')
714
+ st.metric("Total Analyses", total)
715
+ if total > 0:
716
+ st.metric("Fake Rate", f"{(fake_count/total*100):.0f}%")
717
+
718
+ # System status
719
+ st.markdown("---")
720
+ st.markdown("### πŸ”§ Status")
721
+ if API_CONFIGURED:
722
+ st.success("🟒 AI Enhanced")
723
+ else:
724
+ st.warning("🟑 Basic Mode")
725
+
726
+ # Clear history
727
+ st.markdown("---")
728
+ if st.button("πŸ—‘οΈ Clear History", help="Clear all analysis history"):
729
+ st.session_state.analysis_history = []
730
  st.session_state.analysis_complete = False
 
731
  st.session_state.current_results = {}
732
+ st.success("History cleared!")
733
+ time.sleep(1)
734
+ st.rerun()
735
 
736
+ # Main content
737
+ if page == "πŸš€ Live Analysis":
738
+ render_hero_section()
739
+
740
  if not API_CONFIGURED:
741
+ st.info("πŸ”‘ **Optional Setup:** Add GOOGLE_API_KEY in Space Settings β†’ Variables and Secrets for enhanced AI summaries. The platform works perfectly without it using intelligent fallback analysis.")
742
+
 
743
  render_analysis_interface()
744
+
745
  # Display results
746
  if st.session_state.analysis_complete and st.session_state.current_results:
747
  st.markdown("---")
748
  st.markdown("## πŸ“Š Analysis Results")
749
  render_analysis_results(st.session_state.current_results)
750
 
751
+ elif page == "πŸ“œ History":
 
752
  st.markdown("# πŸ“œ Analysis History")
 
 
 
 
 
 
 
 
 
 
 
 
753
 
754
+ if st.session_state.analysis_history:
755
+ # Summary stats
756
+ total = len(st.session_state.analysis_history)
757
+ fake_count = sum(1 for h in st.session_state.analysis_history if h.get('verdict') == 'FAKE')
758
+ real_count = sum(1 for h in st.session_state.analysis_history if h.get('verdict') == 'REAL')
759
+
760
+ st.markdown("### πŸ“ˆ Summary Statistics")
761
+ stat_cols = st.columns(3)
762
+ with stat_cols[0]:
763
+ st.metric("Total Analyses", total)
764
+ with stat_cols[1]:
765
+ st.metric("Fake Content", fake_count)
766
+ with stat_cols[2]:
767
+ st.metric("Real Content", real_count)
768
+
769
+ st.markdown("---")
770
+
771
+ # Display history
772
+ for i, result in enumerate(st.session_state.analysis_history):
773
+ with st.expander(f"#{i+1} - {result.get('verdict', 'Unknown')} | {result.get('input', 'No input')}", expanded=(i==0)):
774
+ render_analysis_results(result)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
775
  else:
776
+ st.info("πŸ“š **No Analysis History** - Your analysis history will appear here after you perform some fact-checking analyses. Start by going to the Live Analysis page and analyzing some content!")
777
 
778
+ elif page == "ℹ️ About":
 
779
  st.markdown("# πŸ”¬ About Credo AI")
780
+
781
  st.markdown("""
782
  <div class="glass-card">
783
  <h2 style="color: #6366f1; margin-bottom: 1rem;">πŸš€ Revolutionary Detection Technology</h2>
 
788
  </p>
789
  </div>
790
  """, unsafe_allow_html=True)
791
+
792
+ # Technical details
793
+ tab1, tab2, tab3 = st.tabs(["🧠 AI Architecture", "πŸ“Š Performance", "πŸ”¬ Technology"])
794
+
795
  with tab1:
796
  st.markdown("""
797
  ### ⚑ Brain 2: The Specialist
798
  - **Model:** `Arko007/fact-check1-v3-final`
799
+ - **Function:** Rapid FAKE/REAL binary classification
800
+ - **Training:** 80,000+ verified news articles
801
+ - **Performance:** 99.9% accuracy on benchmarks
802
  - **Speed:** Sub-second inference time
803
+
804
+ ### 🧠 Brain 1: The Nuance Expert
805
  - **Model:** `Arko007/fact-check-v1`
806
+ - **Function:** Multi-class contextual analysis
807
+ - **Training:** LIAR dataset with political fact-checking
808
  - **Specialization:** Detects subtle misinformation patterns
809
  - **Capability:** Handles complex and ambiguous claims
810
+
811
+ ### ✨ Gemini Integration
812
+ - **Role:** Intelligent synthesis layer
813
+ - **Function:** Converts technical AI outputs to insights
814
+ - **Value:** Makes AI decisions accessible to everyone
 
815
  """)
816
+
817
  with tab2:
818
+ st.markdown("### πŸ“ˆ Performance Metrics")
819
 
 
820
  metrics_data = {
821
+ 'Metric': ['Accuracy', 'Precision', 'Recall', 'F1-Score', 'Speed'],
822
+ 'Brain 1': ['94.2%', '93.8%', '92.1%', '92.9%', '1.2s'],
823
+ 'Brain 2': ['99.9%', '99.8%', '99.7%', '99.7%', '0.8s'],
824
+ 'Combined': ['99.2%', '99.1%', '98.9%', '99.0%', '2.1s']
825
  }
826
+
827
+ st.dataframe(pd.DataFrame(metrics_data), use_container_width=True, hide_index=True)
828
+
 
829
  st.success("πŸ† **Industry Leading:** Credo AI consistently outperforms single-model approaches by 15-25% across major misinformation datasets.")
830
+
831
  with tab3:
832
  st.markdown("""
833
  ### πŸ› οΈ Technology Stack
834
+
835
  **πŸ€– Core AI/ML:**
836
  - PyTorch deep learning framework
837
  - Transformers library for model handling
838
  - BERT-based language understanding
839
  - Advanced fine-tuning techniques
840
+
 
841
  **🌐 Web & Integration:**
842
  - Streamlit for responsive UI
843
+ - Beautiful Soup for web scraping
844
  - Google Generative AI (Gemini 2.0)
 
845
  - Custom CSS for enhanced UX
846
+
847
+ **⚑ Performance:**
848
  - Intelligent caching system
849
  - Memory-efficient processing
 
850
  - Mobile-responsive design
 
 
 
 
851
  - Privacy-first architecture
 
852
  """)
853
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854
  # Footer
855
  st.markdown("""
856
  <div class="footer-enhanced">
 
879
  Powered by Advanced AI β€’ Making Truth Accessible to Everyone
880
  </div>
881
  </div>
882
+ """, unsafe_allow_html=True)