Ahmedik95316 commited on
Commit
611295b
·
verified ·
1 Parent(s): 6c4684c

Update app/streamlit_app.py

Browse files
Files changed (1) hide show
  1. app/streamlit_app.py +2 -422
app/streamlit_app.py CHANGED
@@ -279,116 +279,6 @@ class StreamlitAppManager:
279
  logger.warning(f"Could not fetch traffic status: {e}")
280
  return None
281
 
282
- def trigger_manual_operation(self, operation_type: str, parameters: dict = None, async_execution: bool = True) -> dict:
283
- """Trigger a manual operation via API"""
284
- try:
285
- if not self.api_available:
286
- return {'error': 'API not available'}
287
-
288
- request_data = {
289
- 'operation_type': operation_type,
290
- 'parameters': parameters or {},
291
- 'async_execution': async_execution,
292
- 'priority': 5,
293
- 'timeout_seconds': 300
294
- }
295
-
296
- response = self.session.post(
297
- f"{self.config['api_url']}/operations/trigger",
298
- json=request_data,
299
- timeout=30
300
- )
301
-
302
- if response.status_code == 200:
303
- return response.json()
304
- else:
305
- return {'error': f'API Error: {response.status_code} - {response.text}'}
306
-
307
- except Exception as e:
308
- return {'error': f'Request failed: {str(e)}'}
309
-
310
- def get_operation_status(self, operation_id: str) -> dict:
311
- """Get status of a triggered operation"""
312
- try:
313
- if not self.api_available:
314
- return {'error': 'API not available'}
315
-
316
- response = self.session.get(
317
- f"{self.config['api_url']}/operations/{operation_id}/status",
318
- timeout=10
319
- )
320
-
321
- if response.status_code == 200:
322
- return response.json()
323
- else:
324
- return {'error': f'API Error: {response.status_code}'}
325
-
326
- except Exception as e:
327
- return {'error': f'Request failed: {str(e)}'}
328
-
329
- def list_operations(self, status_filter: str = None, limit: int = 20) -> dict:
330
- """List recent operations"""
331
- try:
332
- if not self.api_available:
333
- return {'error': 'API not available'}
334
-
335
- params = {'limit': limit}
336
- if status_filter:
337
- params['status'] = status_filter
338
-
339
- response = self.session.get(
340
- f"{self.config['api_url']}/operations",
341
- params=params,
342
- timeout=10
343
- )
344
-
345
- if response.status_code == 200:
346
- return {'operations': response.json()}
347
- else:
348
- return {'error': f'API Error: {response.status_code}'}
349
-
350
- except Exception as e:
351
- return {'error': f'Request failed: {str(e)}'}
352
-
353
- def get_available_operation_types(self) -> dict:
354
- """Get available operation types"""
355
- try:
356
- if not self.api_available:
357
- return {'error': 'API not available'}
358
-
359
- response = self.session.get(
360
- f"{self.config['api_url']}/operations/types",
361
- timeout=10
362
- )
363
-
364
- if response.status_code == 200:
365
- return response.json()
366
- else:
367
- return {'error': f'API Error: {response.status_code}'}
368
-
369
- except Exception as e:
370
- return {'error': f'Request failed: {str(e)}'}
371
-
372
- def cancel_operation(self, operation_id: str) -> dict:
373
- """Cancel a pending operation"""
374
- try:
375
- if not self.api_available:
376
- return {'error': 'API not available'}
377
-
378
- response = self.session.post(
379
- f"{self.config['api_url']}/operations/{operation_id}/cancel",
380
- timeout=10
381
- )
382
-
383
- if response.status_code == 200:
384
- return response.json()
385
- else:
386
- return {'error': f'API Error: {response.status_code}'}
387
-
388
- except Exception as e:
389
- return {'error': f'Request failed: {str(e)}'}
390
-
391
-
392
 
393
  # Initialize app manager
394
  app_manager = StreamlitAppManager()
@@ -1165,15 +1055,14 @@ def main():
1165
  '<div class="error-message">🔴 API Service: Offline</div>', unsafe_allow_html=True)
1166
 
1167
  # Main content area
1168
- tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8 = st.tabs([
1169
  "🔍 Prediction",
1170
  "📊 Batch Analysis",
1171
  "📈 Analytics",
1172
  "🎯 Model Training",
1173
  "📋 Logs",
1174
  "⚙️ System Status",
1175
- "📊 Monitoring", # New monitoring tab
1176
- "⚙️ Manual Triggers"
1177
  ])
1178
 
1179
 
@@ -1704,11 +1593,6 @@ def main():
1704
  st.divider()
1705
  render_deployment_status()
1706
 
1707
-
1708
- # Tab 8: Manual Triggers
1709
- render_manual_triggers_tab()
1710
-
1711
-
1712
  def render_system_status():
1713
  """Render system status tab"""
1714
  st.header("System Status & Monitoring")
@@ -1933,310 +1817,6 @@ def render_deployment_status():
1933
  else:
1934
  st.warning("Deployment status not available")
1935
 
1936
-
1937
- # Manual Triggering Endpoint UI
1938
- def render_manual_triggers_tab():
1939
- """Render the manual triggers tab"""
1940
- st.header("⚙️ Manual System Operations")
1941
-
1942
- # Quick status check
1943
- col1, col2 = st.columns([3, 1])
1944
-
1945
- with col1:
1946
- if st.session_state.get('last_operation_check'):
1947
- last_check = st.session_state.last_operation_check
1948
- st.info(f"Last operation check: {last_check}")
1949
- else:
1950
- st.info("No recent operations")
1951
-
1952
- with col2:
1953
- if st.button("🔄 Refresh Status", use_container_width=True):
1954
- st.session_state.last_operation_check = datetime.now().strftime('%H:%M:%S')
1955
- st.rerun()
1956
-
1957
- # Initialize session state for operations
1958
- if 'triggered_operations' not in st.session_state:
1959
- st.session_state.triggered_operations = {}
1960
-
1961
- # Operation trigger section
1962
- st.subheader("🚀 Available Operations")
1963
-
1964
- # Get available operation types
1965
- operation_types_data = app_manager.get_available_operation_types()
1966
-
1967
- if 'error' in operation_types_data:
1968
- st.error(f"Could not load operation types: {operation_types_data['error']}")
1969
- return
1970
-
1971
- available_ops = operation_types_data.get('available_operations', {})
1972
-
1973
- # Create operation trigger interface
1974
- col1, col2 = st.columns([2, 1])
1975
-
1976
- with col1:
1977
- # Operation selection
1978
- operation_names = {
1979
- 'data_validation': 'Data Validation',
1980
- 'model_health_check': 'Model Health Check',
1981
- 'system_cleanup': 'System Cleanup',
1982
- 'metrics_export': 'Metrics Export',
1983
- 'log_rotation': 'Log Rotation',
1984
- 'cache_refresh': 'Cache Refresh',
1985
- 'data_quality_audit': 'Data Quality Audit',
1986
- 'prediction_batch_test': 'Prediction Batch Test'
1987
- }
1988
-
1989
- selected_operation = st.selectbox(
1990
- "Select Operation:",
1991
- options=list(operation_names.keys()),
1992
- format_func=lambda x: operation_names[x],
1993
- index=0
1994
- )
1995
-
1996
- # Show operation description
1997
- if selected_operation in available_ops:
1998
- op_info = available_ops[selected_operation]
1999
- st.info(f"**Description:** {op_info['description']}")
2000
- st.caption(f"**Typical Duration:** {op_info['typical_duration']}")
2001
-
2002
- with col2:
2003
- # Execution mode
2004
- async_mode = st.checkbox("Async Execution", value=True,
2005
- help="Run operation in background (recommended)")
2006
-
2007
- # Priority setting
2008
- priority = st.selectbox("Priority", options=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
2009
- index=4, help="1 = Highest, 10 = Lowest")
2010
-
2011
- # Operation-specific parameters
2012
- st.subheader("⚙️ Operation Parameters")
2013
- parameters = {}
2014
-
2015
- if selected_operation == 'data_validation':
2016
- parameters['include_integrity_check'] = st.checkbox("Include Integrity Check", value=True)
2017
-
2018
- elif selected_operation == 'model_health_check':
2019
- parameters['test_count'] = st.number_input("Number of Test Predictions",
2020
- min_value=1, max_value=20, value=4)
2021
-
2022
- elif selected_operation == 'system_cleanup':
2023
- parameters['clean_cache'] = st.checkbox("Clean Cache Files", value=False)
2024
-
2025
- elif selected_operation == 'metrics_export':
2026
- parameters['format'] = st.selectbox("Export Format", options=['json'], index=0)
2027
- parameters['include_raw_data'] = st.checkbox("Include Raw Data", value=False)
2028
-
2029
- elif selected_operation == 'log_rotation':
2030
- col_a, col_b = st.columns(2)
2031
- with col_a:
2032
- parameters['max_file_size_mb'] = st.number_input("Max File Size (MB)",
2033
- min_value=1, max_value=100, value=10)
2034
- with col_b:
2035
- parameters['max_files_per_type'] = st.number_input("Max Files to Keep",
2036
- min_value=1, max_value=20, value=5)
2037
-
2038
- elif selected_operation == 'cache_refresh':
2039
- parameters['regenerate_cache'] = st.checkbox("Regenerate Cache", value=True)
2040
-
2041
- elif selected_operation == 'prediction_batch_test':
2042
- col_a, col_b = st.columns(2)
2043
- with col_a:
2044
- parameters['num_tests'] = st.number_input("Number of Tests",
2045
- min_value=1, max_value=50, value=10)
2046
- with col_b:
2047
- parameters['test_timeout'] = st.number_input("Test Timeout (seconds)",
2048
- min_value=10, max_value=120, value=30)
2049
-
2050
- # Trigger button
2051
- st.divider()
2052
-
2053
- col1, col2, col3 = st.columns([2, 1, 1])
2054
-
2055
- with col1:
2056
- if st.button(f"▶️ Execute {operation_names[selected_operation]}",
2057
- type="primary", use_container_width=True):
2058
-
2059
- with st.spinner(f"Triggering {operation_names[selected_operation]}..."):
2060
- result = app_manager.trigger_manual_operation(
2061
- operation_type=selected_operation,
2062
- parameters=parameters,
2063
- async_execution=async_mode
2064
- )
2065
-
2066
- if 'error' in result:
2067
- st.error(f"Failed to trigger operation: {result['error']}")
2068
- else:
2069
- operation_id = result['operation_id']
2070
- st.session_state.triggered_operations[operation_id] = {
2071
- 'operation_type': selected_operation,
2072
- 'operation_name': operation_names[selected_operation],
2073
- 'triggered_at': datetime.now().isoformat(),
2074
- 'status': result['status'],
2075
- 'async_mode': async_mode
2076
- }
2077
-
2078
- st.success(f"✅ Operation triggered successfully!")
2079
- st.info(f"**Operation ID:** {operation_id}")
2080
- st.info(f"**Status:** {result['status']}")
2081
- st.info(f"**Estimated Duration:** {result['estimated_duration']}")
2082
-
2083
- if async_mode:
2084
- st.info("Operation is running in the background. Check status below.")
2085
-
2086
- with col2:
2087
- # Quick operation buttons
2088
- st.write("**Quick Actions:**")
2089
- if st.button("🔍 Health Check", use_container_width=True):
2090
- result = app_manager.trigger_manual_operation('model_health_check', {}, True)
2091
- if 'operation_id' in result:
2092
- st.success(f"Health check started: {result['operation_id'][:8]}...")
2093
-
2094
- with col3:
2095
- if st.button("🧹 Quick Cleanup", use_container_width=True):
2096
- result = app_manager.trigger_manual_operation('system_cleanup', {'clean_cache': False}, True)
2097
- if 'operation_id' in result:
2098
- st.success(f"Cleanup started: {result['operation_id'][:8]}...")
2099
-
2100
- # Operation status monitoring
2101
- st.divider()
2102
- st.subheader("📊 Operation Status Monitor")
2103
-
2104
- # Recent operations from session state
2105
- if st.session_state.triggered_operations:
2106
- st.write("**Recent Operations (This Session):**")
2107
-
2108
- for op_id, op_info in list(st.session_state.triggered_operations.items())[-5:]:
2109
- with st.expander(f"{op_info['operation_name']} - {op_id[:8]}... ({op_info['status']})"):
2110
- col1, col2 = st.columns([3, 1])
2111
-
2112
- with col1:
2113
- st.write(f"**Operation:** {op_info['operation_name']}")
2114
- st.write(f"**ID:** {op_id}")
2115
- st.write(f"**Triggered:** {op_info['triggered_at']}")
2116
- st.write(f"**Mode:** {'Async' if op_info['async_mode'] else 'Sync'}")
2117
-
2118
- with col2:
2119
- if st.button(f"🔄 Check Status", key=f"check_{op_id}"):
2120
- status_result = app_manager.get_operation_status(op_id)
2121
-
2122
- if 'error' in status_result:
2123
- st.error(f"Status check failed: {status_result['error']}")
2124
- else:
2125
- # Update session state
2126
- st.session_state.triggered_operations[op_id]['status'] = status_result['status']
2127
-
2128
- # Display detailed status
2129
- st.json(status_result)
2130
-
2131
- # Show results if completed
2132
- if status_result['status'] == 'completed' and status_result.get('result_data'):
2133
- st.success("✅ Operation completed successfully!")
2134
- with st.expander("📋 Results"):
2135
- st.json(status_result['result_data'])
2136
-
2137
- elif status_result['status'] == 'failed':
2138
- st.error("❌ Operation failed!")
2139
- if status_result.get('error_message'):
2140
- st.error(f"Error: {status_result['error_message']}")
2141
-
2142
- # All operations from API
2143
- st.subheader("📋 All Recent Operations")
2144
-
2145
- col1, col2, col3 = st.columns(3)
2146
-
2147
- with col1:
2148
- status_filter = st.selectbox(
2149
- "Filter by Status:",
2150
- options=[None, "pending", "running", "completed", "failed", "cancelled"],
2151
- format_func=lambda x: "All" if x is None else x.title()
2152
- )
2153
-
2154
- with col2:
2155
- limit = st.number_input("Max Results", min_value=5, max_value=50, value=20)
2156
-
2157
- with col3:
2158
- if st.button("🔍 Load Operations", use_container_width=True):
2159
- operations_result = app_manager.list_operations(status_filter, limit)
2160
-
2161
- if 'error' in operations_result:
2162
- st.error(f"Failed to load operations: {operations_result['error']}")
2163
- else:
2164
- operations = operations_result.get('operations', [])
2165
-
2166
- if operations:
2167
- st.success(f"Loaded {len(operations)} operations")
2168
-
2169
- # Create operations dataframe
2170
- ops_data = []
2171
- for op in operations:
2172
- ops_data.append({
2173
- 'ID': op['operation_id'][:8] + '...',
2174
- 'Type': op['operation_type'].replace('_', ' ').title(),
2175
- 'Status': op['status'].title(),
2176
- 'Started': op['started_at'][:19] if op['started_at'] else 'N/A',
2177
- 'Duration': f"{op['duration_seconds']:.1f}s" if op.get('duration_seconds') else 'N/A',
2178
- 'Full ID': op['operation_id']
2179
- })
2180
-
2181
- df = pd.DataFrame(ops_data)
2182
-
2183
- # Display operations table
2184
- st.dataframe(df[['ID', 'Type', 'Status', 'Started', 'Duration']],
2185
- use_container_width=True)
2186
-
2187
- # Detailed view for selected operation
2188
- selected_short_id = st.selectbox(
2189
- "View Details for Operation:",
2190
- options=df['ID'].tolist(),
2191
- index=0 if df['ID'].tolist() else None
2192
- )
2193
-
2194
- if selected_short_id:
2195
- selected_full_id = df[df['ID'] == selected_short_id]['Full ID'].iloc[0]
2196
- selected_op = next(op for op in operations if op['operation_id'] == selected_full_id)
2197
-
2198
- st.subheader(f"📄 Operation Details: {selected_short_id}")
2199
-
2200
- col_detail1, col_detail2 = st.columns(2)
2201
-
2202
- with col_detail1:
2203
- st.write(f"**Full ID:** {selected_op['operation_id']}")
2204
- st.write(f"**Type:** {selected_op['operation_type']}")
2205
- st.write(f"**Status:** {selected_op['status']}")
2206
- st.write(f"**Started:** {selected_op['started_at']}")
2207
-
2208
- with col_detail2:
2209
- if selected_op.get('completed_at'):
2210
- st.write(f"**Completed:** {selected_op['completed_at']}")
2211
- if selected_op.get('duration_seconds'):
2212
- st.write(f"**Duration:** {selected_op['duration_seconds']:.2f} seconds")
2213
- if selected_op.get('error_message'):
2214
- st.error(f"**Error:** {selected_op['error_message']}")
2215
-
2216
- # Show logs
2217
- if selected_op.get('logs'):
2218
- with st.expander("📜 Operation Logs"):
2219
- for log_entry in selected_op['logs']:
2220
- st.text(log_entry)
2221
-
2222
- # Show results
2223
- if selected_op.get('result_data'):
2224
- with st.expander("📊 Results Data"):
2225
- st.json(selected_op['result_data'])
2226
-
2227
- # Action buttons
2228
- if selected_op['status'] == 'pending':
2229
- if st.button(f"❌ Cancel Operation", key=f"cancel_{selected_full_id}"):
2230
- cancel_result = app_manager.cancel_operation(selected_full_id)
2231
- if 'error' in cancel_result:
2232
- st.error(f"Cancel failed: {cancel_result['error']}")
2233
- else:
2234
- st.success("Operation cancelled successfully!")
2235
- st.rerun()
2236
- else:
2237
- st.info("No operations found")
2238
-
2239
-
2240
  # Auto-refresh logic
2241
  if st.session_state.auto_refresh:
2242
  time_since_refresh = datetime.now() - st.session_state.last_refresh
 
279
  logger.warning(f"Could not fetch traffic status: {e}")
280
  return None
281
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
 
283
  # Initialize app manager
284
  app_manager = StreamlitAppManager()
 
1055
  '<div class="error-message">🔴 API Service: Offline</div>', unsafe_allow_html=True)
1056
 
1057
  # Main content area
1058
+ tab1, tab2, tab3, tab4, tab5, tab6, tab7 = st.tabs([
1059
  "🔍 Prediction",
1060
  "📊 Batch Analysis",
1061
  "📈 Analytics",
1062
  "🎯 Model Training",
1063
  "📋 Logs",
1064
  "⚙️ System Status",
1065
+ "📊 Monitoring" # New monitoring tab
 
1066
  ])
1067
 
1068
 
 
1593
  st.divider()
1594
  render_deployment_status()
1595
 
 
 
 
 
 
1596
  def render_system_status():
1597
  """Render system status tab"""
1598
  st.header("System Status & Monitoring")
 
1817
  else:
1818
  st.warning("Deployment status not available")
1819
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1820
  # Auto-refresh logic
1821
  if st.session_state.auto_refresh:
1822
  time_since_refresh = datetime.now() - st.session_state.last_refresh