Ahmedik95316 commited on
Commit
070d018
Β·
verified Β·
1 Parent(s): 22bcdb7

Update app/streamlit_app.py

Browse files
Files changed (1) hide show
  1. app/streamlit_app.py +68 -185
app/streamlit_app.py CHANGED
@@ -253,21 +253,20 @@ st.set_page_config(
253
  initial_sidebar_state="expanded"
254
  )
255
 
256
- # Professional Color Scheme - Golden and Complementary Blue Theme
257
  COLORS = {
258
- 'primary': '#DAA520', # Goldenrod
259
- 'secondary': '#1E3A8A', # Royal Blue (complements gold well)
260
  'accent': '#F8F9FA', # Light Grey/White
261
- 'success': '#16A085', # Teal Green
262
- 'warning': '#E67E22', # Orange
263
  'danger': '#E74C3C', # Red
264
- 'info': '#3498DB', # Light Blue
265
- 'dark': '#1F2937', # Dark Grey
266
- 'light': '#F1F5F9', # Very Light Grey
267
  'white': '#FFFFFF', # Pure White
268
- 'text_primary': '#1F2937', # Dark Grey for main text
269
- 'text_secondary': '#6B7280', # Medium Grey for secondary text
270
- 'blue_hover': '#1E40AF' # Darker blue for hover states
271
  }
272
 
273
  # Enhanced Custom CSS with Professional Styling
@@ -288,18 +287,21 @@ st.markdown(f"""
288
  font-size: 3.5rem;
289
  font-weight: 700;
290
  text-align: center;
291
- color: {COLORS['primary']};
 
 
 
292
  margin: 2rem 0;
293
- text-shadow: 0 2px 4px rgba(0,0,0,0.1);
294
  }}
295
 
296
  /* Subtitle */
297
  .subtitle {{
298
  font-family: 'Inter', sans-serif;
299
  font-size: 1.2rem;
300
- font-weight: 500;
301
  text-align: center;
302
- color: {COLORS['secondary']};
303
  margin-bottom: 2rem;
304
  line-height: 1.6;
305
  }}
@@ -373,13 +375,13 @@ st.markdown(f"""
373
 
374
  /* Environment Info */
375
  .environment-info {{
376
- background: {COLORS['accent']};
377
  color: {COLORS['dark']};
378
  padding: 1.5rem;
379
  border-radius: 16px;
380
- border: 1px solid {COLORS['primary']};
381
  margin: 1rem 0;
382
- box-shadow: 0 4px 16px rgba(218, 165, 32, 0.1);
383
  }}
384
 
385
  .environment-info h4 {{
@@ -390,7 +392,7 @@ st.markdown(f"""
390
 
391
  /* Button Styling */
392
  .stButton > button {{
393
- background: {COLORS['primary']};
394
  color: {COLORS['white']};
395
  border: none;
396
  border-radius: 12px;
@@ -398,13 +400,12 @@ st.markdown(f"""
398
  font-weight: 600;
399
  font-family: 'Inter', sans-serif;
400
  transition: all 0.3s ease;
401
- box-shadow: 0 4px 16px rgba(218, 165, 32, 0.3);
402
  }}
403
 
404
  .stButton > button:hover {{
405
- background: {COLORS['blue_hover']};
406
  transform: translateY(-2px);
407
- box-shadow: 0 6px 24px rgba(30, 64, 175, 0.4);
408
  }}
409
 
410
  /* Tab Styling */
@@ -413,35 +414,22 @@ st.markdown(f"""
413
  border-radius: 12px;
414
  padding: 0.5rem;
415
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
416
- border: 1px solid {COLORS['light']};
417
  }}
418
 
419
  .stTabs [data-baseweb="tab"] {{
420
- background: {COLORS['accent']};
421
- border: 2px solid {COLORS['light']};
422
  border-radius: 8px;
423
  color: {COLORS['text_secondary']};
424
  font-weight: 500;
425
  padding: 0.75rem 1.5rem;
426
  margin: 0 0.25rem;
427
  transition: all 0.3s ease;
428
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
429
- }}
430
-
431
- .stTabs [data-baseweb="tab"]:hover {{
432
- border-color: {COLORS['primary']};
433
- background: rgba(218, 165, 32, 0.1);
434
- transform: translateY(-1px);
435
- box-shadow: 0 2px 6px rgba(0,0,0,0.15);
436
  }}
437
 
438
  .stTabs [data-baseweb="tab"][data-state="active"] {{
439
- background: {COLORS['primary']};
440
- border: 2px solid {COLORS['primary']};
441
  color: {COLORS['white']};
442
  font-weight: 600;
443
- transform: translateY(-2px);
444
- box-shadow: 0 4px 12px rgba(218, 165, 32, 0.3);
445
  }}
446
 
447
  /* Sidebar Styling */
@@ -489,26 +477,10 @@ st.markdown(f"""
489
 
490
  /* Progress Bar */
491
  .stProgress > div > div > div > div {{
492
- background: {COLORS['primary']};
493
  border-radius: 8px;
494
  }}
495
 
496
- /* Style widget containers instead of hiding them */
497
- .stRadio, .stCheckbox, .stFileUploader, .stTextInput, .stTextArea, .stSelectbox {{
498
- background-color: {COLORS['accent']} !important;
499
- border: 1px solid {COLORS['light']} !important;
500
- border-radius: 8px !important;
501
- padding: 0.5rem !important;
502
- margin: 0.5rem 0 !important;
503
- }}
504
-
505
- /* Style nested containers to match */
506
- .stRadio > div, .stCheckbox > div, .stFileUploader > div,
507
- .stTextInput > div, .stTextArea > div, .stSelectbox > div {{
508
- background-color: transparent !important;
509
- border: none !important;
510
- }}
511
-
512
  /* Alert Styling */
513
  .alert-critical {{
514
  background: linear-gradient(135deg, {COLORS['danger']}20 0%, {COLORS['danger']}10 100%);
@@ -561,7 +533,7 @@ st.markdown(f"""
561
  display: inline-block;
562
  width: 4px;
563
  height: 24px;
564
- background: {COLORS['primary']};
565
  margin-right: 12px;
566
  border-radius: 2px;
567
  }}
@@ -732,8 +704,8 @@ def create_confidence_gauge(confidence: float, prediction: str):
732
  'bar': {'color': COLORS['danger'] if prediction == "Fake" else COLORS['success']},
733
  'steps': [
734
  {'range': [0, 50], 'color': COLORS['light']},
735
- {'range': [50, 80], 'color': 'rgba(243, 156, 18, 0.3)'}, # Warning color with transparency
736
- {'range': [80, 100], 'color': 'rgba(39, 174, 96, 0.3)'} # Success color with transparency
737
  ],
738
  'threshold': {
739
  'line': {'color': COLORS['primary'], 'width': 4},
@@ -843,19 +815,17 @@ def main():
843
  with tab1:
844
  st.markdown('<h2 class="section-header">🎯 Single Text Analysis</h2>', unsafe_allow_html=True)
845
 
846
- # Input methods with custom styling wrapper
847
  col1, col2 = st.columns([3, 1])
848
  with col1:
849
  st.markdown('<h3 class="subsection-header">Input Method</h3>', unsafe_allow_html=True)
850
  with col2:
851
- st.markdown('<div style="background: transparent; padding: 0;">', unsafe_allow_html=True)
852
  input_method = st.radio(
853
  "Choose input method:",
854
  ["Type Text", "Upload File"],
855
  horizontal=True,
856
  label_visibility="collapsed"
857
  )
858
- st.markdown('</div>', unsafe_allow_html=True)
859
 
860
  user_text = ""
861
 
@@ -1645,14 +1615,16 @@ def render_logs_tab():
1645
  "Alerts Log": path_manager.get_logs_path("monitor/alerts.json")
1646
  }
1647
 
1648
- col1, col2, col3 = st.columns([2, 1, 1])
1649
-
1650
- with col1:
1651
- selected_log = st.selectbox("Select log file:", list(log_files.keys()))
1652
- with col2:
1653
- max_entries = st.number_input("Max entries:", min_value=10, max_value=1000, value=50)
1654
- with col3:
1655
- auto_refresh_logs = st.checkbox("Auto refresh", value=False)
 
 
1656
 
1657
  if st.button("πŸ“‚ Load Log", type="primary", use_container_width=True) or auto_refresh_logs:
1658
  log_path = log_files[selected_log]
@@ -1760,130 +1732,41 @@ def render_system_status_tab():
1760
  </div>
1761
  """, unsafe_allow_html=True)
1762
 
1763
- # Enhanced Health components display
1764
  model_health = health_data.get('model_health', {})
1765
  system_health = health_data.get('system_health', {})
1766
  api_health = health_data.get('api_health', {})
1767
 
1768
- # Create professional health cards
1769
  col1, col2, col3 = st.columns(3)
1770
 
1771
  with col1:
1772
- st.markdown(f"""
1773
- <div class="status-card" style="border: 2px solid {COLORS['primary']};">
1774
- <div style="text-align: center; padding: 1rem;">
1775
- <div style="color: {COLORS['primary']}; font-size: 2rem; margin-bottom: 0.5rem;">πŸ€–</div>
1776
- <h3 style="color: {COLORS['primary']}; margin: 0.5rem 0; font-weight: 600;">Model Health</h3>
1777
- <div style="margin-top: 1rem;">
1778
- """, unsafe_allow_html=True)
1779
-
1780
- status_val = model_health.get('status', 'unknown')
1781
- if status_val == 'healthy':
1782
- st.markdown(f'<div style="color: {COLORS["success"]}; font-weight: 600; margin: 0.5rem 0;">Status: βœ… Healthy</div>', unsafe_allow_html=True)
1783
- else:
1784
- st.markdown(f'<div style="color: {COLORS["danger"]}; font-weight: 600; margin: 0.5rem 0;">Status: ❌ Unhealthy</div>', unsafe_allow_html=True)
1785
-
1786
- # Key model metrics
1787
- last_check = model_health.get('last_check', 'Unknown')
1788
- if last_check != 'Unknown':
1789
- try:
1790
- from datetime import datetime
1791
- check_time = datetime.fromisoformat(last_check.replace('Z', '+00:00'))
1792
- formatted_time = check_time.strftime('%H:%M:%S')
1793
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-size: 0.9rem;">Last Check: {formatted_time}</div>', unsafe_allow_html=True)
1794
- except:
1795
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-size: 0.9rem;">Last Check: {last_check}</div>', unsafe_allow_html=True)
1796
-
1797
- model_available = model_health.get('model_available', False)
1798
- pipeline_available = model_health.get('pipeline_available', False)
1799
- vectorizer_available = model_health.get('vectorizer_available', False)
1800
-
1801
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-size: 0.9rem;">Model Available: {"βœ…" if model_available else "❌"}</div>', unsafe_allow_html=True)
1802
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-size: 0.9rem;">Pipeline Available: {"βœ…" if pipeline_available else "❌"}</div>', unsafe_allow_html=True)
1803
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-size: 0.9rem;">Vectorizer Available: {"βœ…" if vectorizer_available else "❌"}</div>', unsafe_allow_html=True)
1804
-
1805
- # Model paths
1806
- vectorizer_path = model_health.get('vectorizer_path', 'Unknown')
1807
- pipeline_path = model_health.get('pipeline_path', 'Unknown')
1808
- if vectorizer_path != 'Unknown':
1809
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-size: 0.8rem; margin-top: 0.5rem;">Vectorizer Path: {vectorizer_path}</div>', unsafe_allow_html=True)
1810
- if pipeline_path != 'Unknown':
1811
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-size: 0.8rem;">Pipeline Path: {pipeline_path}</div>', unsafe_allow_html=True)
1812
-
1813
- st.markdown("""
1814
- </div>
1815
- </div>
1816
- </div>
1817
- """, unsafe_allow_html=True)
1818
 
1819
  with col2:
1820
- st.markdown(f"""
1821
- <div class="status-card" style="border: 2px solid {COLORS['info']};">
1822
- <div style="text-align: center; padding: 1rem;">
1823
- <div style="color: {COLORS['info']}; font-size: 2rem; margin-bottom: 0.5rem;">πŸ’»</div>
1824
- <h3 style="color: {COLORS['info']}; margin: 0.5rem 0; font-weight: 600;">System Health</h3>
1825
- <div style="margin-top: 1rem;">
1826
- """, unsafe_allow_html=True)
1827
-
1828
- cpu_percent = system_health.get('cpu_percent', 0)
1829
- memory_percent = system_health.get('memory_percent', 0)
1830
- disk_percent = system_health.get('disk_percent', 0)
1831
-
1832
- # CPU Usage
1833
- cpu_color = COLORS['success'] if cpu_percent < 70 else COLORS['warning'] if cpu_percent < 85 else COLORS['danger']
1834
- st.markdown(f'<div style="color: {cpu_color}; font-weight: 600; margin: 0.5rem 0;">CPU Percent</div>', unsafe_allow_html=True)
1835
- st.markdown(f'<div style="color: {cpu_color}; font-size: 1.5rem; font-weight: 700;">{cpu_percent:.1f}%</div>', unsafe_allow_html=True)
1836
-
1837
- # Memory Usage
1838
- memory_color = COLORS['success'] if memory_percent < 70 else COLORS['warning'] if memory_percent < 85 else COLORS['danger']
1839
- st.markdown(f'<div style="color: {memory_color}; font-weight: 600; margin: 0.5rem 0;">Memory Percent</div>', unsafe_allow_html=True)
1840
- st.markdown(f'<div style="color: {memory_color}; font-size: 1.5rem; font-weight: 700;">{memory_percent:.1f}%</div>', unsafe_allow_html=True)
1841
-
1842
- # Disk Usage
1843
- disk_color = COLORS['success'] if disk_percent < 70 else COLORS['warning'] if disk_percent < 85 else COLORS['danger']
1844
- st.markdown(f'<div style="color: {disk_color}; font-weight: 600; margin: 0.5rem 0;">Disk Percent</div>', unsafe_allow_html=True)
1845
- st.markdown(f'<div style="color: {disk_color}; font-size: 1.5rem; font-weight: 700;">{disk_percent:.1f}%</div>', unsafe_allow_html=True)
1846
-
1847
- # Uptime
1848
- uptime = system_health.get('uptime', 0)
1849
- uptime_hours = uptime / 3600 if uptime else 0
1850
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-weight: 600; margin: 0.5rem 0;">Uptime</div>', unsafe_allow_html=True)
1851
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-size: 1.2rem; font-weight: 600;">{uptime_hours:.1f}h</div>', unsafe_allow_html=True)
1852
-
1853
- st.markdown("""
1854
- </div>
1855
- </div>
1856
- </div>
1857
- """, unsafe_allow_html=True)
1858
 
1859
  with col3:
1860
- st.markdown(f"""
1861
- <div class="status-card" style="border: 2px solid {COLORS['secondary']};">
1862
- <div style="text-align: center; padding: 1rem;">
1863
- <div style="color: {COLORS['secondary']}; font-size: 2rem; margin-bottom: 0.5rem;">🌐</div>
1864
- <h3 style="color: {COLORS['secondary']}; margin: 0.5rem 0; font-weight: 600;">API Health</h3>
1865
- <div style="margin-top: 1rem;">
1866
- """, unsafe_allow_html=True)
1867
-
1868
- rate_limit_active = api_health.get('rate_limit_active', False)
1869
- active_connections = api_health.get('active_connections', 0)
1870
-
1871
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-weight: 600; margin: 0.5rem 0;">Rate Limit Active: {"βœ…" if rate_limit_active else "❌"}</div>', unsafe_allow_html=True)
1872
-
1873
- st.markdown(f'<div style="color: {COLORS["secondary"]}; font-weight: 600; margin: 0.5rem 0;">Active Connections</div>', unsafe_allow_html=True)
1874
- st.markdown(f'<div style="color: {COLORS["secondary"]}; font-size: 1.5rem; font-weight: 700;">{active_connections}</div>', unsafe_allow_html=True)
1875
-
1876
- # Add more API health metrics if available
1877
  for key, value in api_health.items():
1878
- if key not in ['rate_limit_active', 'active_connections'] and not key.startswith('_'):
1879
- display_key = key.replace('_', ' ').title()
1880
- st.markdown(f'<div style="color: {COLORS["text_secondary"]}; font-size: 0.9rem; margin: 0.2rem 0;">{display_key}: {value}</div>', unsafe_allow_html=True)
1881
-
1882
- st.markdown("""
1883
- </div>
1884
- </div>
1885
- </div>
1886
- """, unsafe_allow_html=True)
1887
 
1888
  except Exception as e:
1889
  st.markdown(f"""
@@ -2297,9 +2180,9 @@ def render_cv_results_section():
2297
  if 'model_version' in cv_results:
2298
  st.markdown(f"""
2299
  <div class="info-message">
2300
- <strong>Model:</strong> {cv_results.get('model_version', 'Unknown')} |
2301
- <strong>Type:</strong> {cv_results.get('model_type', 'Unknown')} |
2302
- <strong>Trained:</strong> {cv_results.get('training_timestamp', 'Unknown')}
2303
  </div>
2304
  """, unsafe_allow_html=True)
2305
 
@@ -2366,8 +2249,8 @@ def render_model_comparison_section():
2366
 
2367
  st.markdown(f"""
2368
  <div class="info-message">
2369
- <strong>Comparison:</strong> {models_compared.get('model1_name', 'Model 1')} vs {models_compared.get('model2_name', 'Model 2')} |
2370
- <strong>Timestamp:</strong> {comparison_results.get('comparison_timestamp', 'Unknown')}
2371
  </div>
2372
  """, unsafe_allow_html=True)
2373
 
 
253
  initial_sidebar_state="expanded"
254
  )
255
 
256
+ # Professional Color Scheme - Sophisticated Gold/Grey/White Theme
257
  COLORS = {
258
+ 'primary': '#D4AF37', # Gold
259
+ 'secondary': '#2C3E50', # Dark Grey
260
  'accent': '#F8F9FA', # Light Grey/White
261
+ 'success': '#27AE60', # Green
262
+ 'warning': '#F39C12', # Orange
263
  'danger': '#E74C3C', # Red
264
+ 'info': '#3498DB', # Blue
265
+ 'dark': '#34495E', # Darker Grey
266
+ 'light': '#ECF0F1', # Very Light Grey
267
  'white': '#FFFFFF', # Pure White
268
+ 'text_primary': '#2C3E50', # Dark Grey for main text
269
+ 'text_secondary': '#7F8C8D' # Medium Grey for secondary text
 
270
  }
271
 
272
  # Enhanced Custom CSS with Professional Styling
 
287
  font-size: 3.5rem;
288
  font-weight: 700;
289
  text-align: center;
290
+ background: linear-gradient(135deg, {COLORS['primary']} 0%, {COLORS['warning']} 100%);
291
+ -webkit-background-clip: text;
292
+ -webkit-text-fill-color: transparent;
293
+ background-clip: text;
294
  margin: 2rem 0;
295
+ text-shadow: 0 4px 8px rgba(0,0,0,0.1);
296
  }}
297
 
298
  /* Subtitle */
299
  .subtitle {{
300
  font-family: 'Inter', sans-serif;
301
  font-size: 1.2rem;
302
+ font-weight: 400;
303
  text-align: center;
304
+ color: {COLORS['text_secondary']};
305
  margin-bottom: 2rem;
306
  line-height: 1.6;
307
  }}
 
375
 
376
  /* Environment Info */
377
  .environment-info {{
378
+ background: linear-gradient(135deg, {COLORS['primary']}20 0%, {COLORS['primary']}10 100%);
379
  color: {COLORS['dark']};
380
  padding: 1.5rem;
381
  border-radius: 16px;
382
+ border: 1px solid {COLORS['primary']}40;
383
  margin: 1rem 0;
384
+ box-shadow: 0 4px 16px rgba(212, 175, 55, 0.1);
385
  }}
386
 
387
  .environment-info h4 {{
 
392
 
393
  /* Button Styling */
394
  .stButton > button {{
395
+ background: linear-gradient(135deg, {COLORS['primary']} 0%, {COLORS['warning']} 100%);
396
  color: {COLORS['white']};
397
  border: none;
398
  border-radius: 12px;
 
400
  font-weight: 600;
401
  font-family: 'Inter', sans-serif;
402
  transition: all 0.3s ease;
403
+ box-shadow: 0 4px 16px rgba(212, 175, 55, 0.3);
404
  }}
405
 
406
  .stButton > button:hover {{
 
407
  transform: translateY(-2px);
408
+ box-shadow: 0 6px 24px rgba(212, 175, 55, 0.4);
409
  }}
410
 
411
  /* Tab Styling */
 
414
  border-radius: 12px;
415
  padding: 0.5rem;
416
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
 
417
  }}
418
 
419
  .stTabs [data-baseweb="tab"] {{
420
+ background: transparent;
 
421
  border-radius: 8px;
422
  color: {COLORS['text_secondary']};
423
  font-weight: 500;
424
  padding: 0.75rem 1.5rem;
425
  margin: 0 0.25rem;
426
  transition: all 0.3s ease;
 
 
 
 
 
 
 
 
427
  }}
428
 
429
  .stTabs [data-baseweb="tab"][data-state="active"] {{
430
+ background: linear-gradient(135deg, {COLORS['primary']} 0%, {COLORS['warning']} 100%);
 
431
  color: {COLORS['white']};
432
  font-weight: 600;
 
 
433
  }}
434
 
435
  /* Sidebar Styling */
 
477
 
478
  /* Progress Bar */
479
  .stProgress > div > div > div > div {{
480
+ background: linear-gradient(135deg, {COLORS['primary']} 0%, {COLORS['warning']} 100%);
481
  border-radius: 8px;
482
  }}
483
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
  /* Alert Styling */
485
  .alert-critical {{
486
  background: linear-gradient(135deg, {COLORS['danger']}20 0%, {COLORS['danger']}10 100%);
 
533
  display: inline-block;
534
  width: 4px;
535
  height: 24px;
536
+ background: linear-gradient(135deg, {COLORS['primary']} 0%, {COLORS['warning']} 100%);
537
  margin-right: 12px;
538
  border-radius: 2px;
539
  }}
 
704
  'bar': {'color': COLORS['danger'] if prediction == "Fake" else COLORS['success']},
705
  'steps': [
706
  {'range': [0, 50], 'color': COLORS['light']},
707
+ {'range': [50, 80], 'color': COLORS['warning'] + '40'},
708
+ {'range': [80, 100], 'color': COLORS['success'] + '40'}
709
  ],
710
  'threshold': {
711
  'line': {'color': COLORS['primary'], 'width': 4},
 
815
  with tab1:
816
  st.markdown('<h2 class="section-header">🎯 Single Text Analysis</h2>', unsafe_allow_html=True)
817
 
818
+ # Input methods with professional styling
819
  col1, col2 = st.columns([3, 1])
820
  with col1:
821
  st.markdown('<h3 class="subsection-header">Input Method</h3>', unsafe_allow_html=True)
822
  with col2:
 
823
  input_method = st.radio(
824
  "Choose input method:",
825
  ["Type Text", "Upload File"],
826
  horizontal=True,
827
  label_visibility="collapsed"
828
  )
 
829
 
830
  user_text = ""
831
 
 
1615
  "Alerts Log": path_manager.get_logs_path("monitor/alerts.json")
1616
  }
1617
 
1618
+ # Group log controls in container
1619
+ with st.container():
1620
+ col1, col2, col3 = st.columns([2, 1, 1])
1621
+
1622
+ with col1:
1623
+ selected_log = st.selectbox("Select log file:", list(log_files.keys()))
1624
+ with col2:
1625
+ max_entries = st.number_input("Max entries:", min_value=10, max_value=1000, value=50)
1626
+ with col3:
1627
+ auto_refresh_logs = st.checkbox("Auto refresh", value=False)
1628
 
1629
  if st.button("πŸ“‚ Load Log", type="primary", use_container_width=True) or auto_refresh_logs:
1630
  log_path = log_files[selected_log]
 
1732
  </div>
1733
  """, unsafe_allow_html=True)
1734
 
1735
+ # Health components
1736
  model_health = health_data.get('model_health', {})
1737
  system_health = health_data.get('system_health', {})
1738
  api_health = health_data.get('api_health', {})
1739
 
 
1740
  col1, col2, col3 = st.columns(3)
1741
 
1742
  with col1:
1743
+ st.markdown('<h4>πŸ€– Model Health</h4>', unsafe_allow_html=True)
1744
+ for key, value in model_health.items():
1745
+ if key not in ['test_prediction', 'model_path', 'data_path', 'environment', 'file_exists']:
1746
+ display_key = key.replace('_', ' ').title()
1747
+ if isinstance(value, bool):
1748
+ status_icon = "βœ…" if value else "❌"
1749
+ st.write(f"**{display_key}:** {status_icon}")
1750
+ else:
1751
+ st.write(f"**{display_key}:** {value}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1752
 
1753
  with col2:
1754
+ st.markdown('<h4>πŸ’» System Health</h4>', unsafe_allow_html=True)
1755
+ for key, value in system_health.items():
1756
+ display_key = key.replace('_', ' ').title()
1757
+ if 'percent' in key:
1758
+ st.metric(display_key, f"{value:.1f}%")
1759
+ elif 'uptime' in key:
1760
+ uptime_hours = value / 3600
1761
+ st.metric(display_key, f"{uptime_hours:.1f}h")
1762
+ else:
1763
+ st.write(f"**{display_key}:** {value}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1764
 
1765
  with col3:
1766
+ st.markdown('<h4>🌐 API Health</h4>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1767
  for key, value in api_health.items():
1768
+ display_key = key.replace('_', ' ').title()
1769
+ st.write(f"**{display_key}:** {value}")
 
 
 
 
 
 
 
1770
 
1771
  except Exception as e:
1772
  st.markdown(f"""
 
2180
  if 'model_version' in cv_results:
2181
  st.markdown(f"""
2182
  <div class="info-message">
2183
+ **Model:** {cv_results.get('model_version', 'Unknown')} |
2184
+ **Type:** {cv_results.get('model_type', 'Unknown')} |
2185
+ **Trained:** {cv_results.get('training_timestamp', 'Unknown')}
2186
  </div>
2187
  """, unsafe_allow_html=True)
2188
 
 
2249
 
2250
  st.markdown(f"""
2251
  <div class="info-message">
2252
+ **Comparison:** {models_compared.get('model1_name', 'Model 1')} vs {models_compared.get('model2_name', 'Model 2')} |
2253
+ **Timestamp:** {comparison_results.get('comparison_timestamp', 'Unknown')}
2254
  </div>
2255
  """, unsafe_allow_html=True)
2256