RathodHarish commited on
Commit
a63c544
·
verified ·
1 Parent(s): f070cb5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -31
app.py CHANGED
@@ -5,7 +5,7 @@ import logging
5
  import plotly.express as px
6
  import plotly.graph_objects as go
7
  from sklearn.ensemble import IsolationForest
8
- from concurrent.futures import ThreadPoolExecutor # Added missing import
9
  import os
10
  import io
11
  import time
@@ -315,21 +315,25 @@ def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights
315
  return None
316
 
317
  # Main processing function
318
- async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_range, last_modified_state, cached_df_state, cached_filtered_df_state):
319
  start_time = time.time()
320
  try:
321
- if not file_obj:
322
- return "No file uploaded.", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, "No anomalies detected.", "No AMC reminders.", "No insights generated.", None, last_modified_state, cached_df_state, cached_filtered_df_state
323
 
324
- file_path = file_obj.name
325
- current_modified_time = os.path.getmtime(file_path)
326
- if last_modified_state and current_modified_time == last_modified_state and cached_filtered_df_state is not None:
 
 
 
 
327
  filtered_df = cached_filtered_df_state
328
  else:
329
- if cached_df_state is None or current_modified_time != last_modified_state:
330
  logging.info(f"Processing file: {file_path}")
331
  if not file_path.endswith(".csv"):
332
- return "Please upload a CSV file.", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, "", "", "", None, last_modified_state, cached_df_state, cached_filtered_df_state
333
 
334
  required_columns = ["device_id", "log_type", "status", "timestamp", "usage_hours", "downtime", "amc_date"]
335
  dtypes = {
@@ -343,14 +347,14 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
343
  df = pd.read_csv(file_path, dtype=dtypes)
344
  missing_columns = [col for col in required_columns if col not in df.columns]
345
  if missing_columns:
346
- return f"Missing columns: {missing_columns}", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, None, None, None, None, last_modified_state, cached_df_state, cached_filtered_df_state
347
 
348
  df["timestamp"] = pd.to_datetime(df["timestamp"], errors='coerce')
349
  df["amc_date"] = pd.to_datetime(df["amc_date"], errors='coerce')
350
  if df["timestamp"].dt.tz is None:
351
  df["timestamp"] = df["timestamp"].dt.tz_localize('UTC').dt.tz_convert('Asia/Kolkata')
352
  if df.empty:
353
- return "No data available.", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, None, None, None, None, last_modified_state, df, cached_filtered_df_state
354
  else:
355
  df = cached_df_state
356
 
@@ -368,7 +372,7 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
368
  filtered_df = filtered_df[(filtered_df['timestamp'] >= start_date) & (filtered_df['timestamp'] <= end_date)]
369
 
370
  if filtered_df.empty:
371
- return "No data after applying filters.", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, None, None, None, None, last_modified_state, df, filtered_df
372
 
373
  # Generate table for preview
374
  preview_df = filtered_df[['device_id', 'log_type', 'status', 'timestamp', 'usage_hours', 'downtime', 'amc_date']].head(5)
@@ -407,10 +411,10 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
407
  if elapsed_time > 3:
408
  logging.warning(f"Processing time exceeded 3 seconds: {elapsed_time:.2f} seconds")
409
 
410
- return (summary, preview_html, usage_chart, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, anomalies, amc_reminders, insights, None, current_modified_time, df, filtered_df)
411
  except Exception as e:
412
  logging.error(f"Failed to process file: {str(e)}")
413
- return f"Error: {str(e)}", pd.DataFrame(), None, '<p>Error processing data.</p>', None, None, None, None, None, None, None, None, last_modified_state, cached_df_state, cached_filtered_df_state
414
 
415
  # Generate PDF separately
416
  async def generate_pdf(summary, preview_html, usage_chart, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, anomalies, amc_reminders, insights):
@@ -423,22 +427,17 @@ async def generate_pdf(summary, preview_html, usage_chart, device_cards, daily_l
423
  return None
424
 
425
  # Update filters
426
- def update_filters(file_obj, current_file_state):
427
- if not file_obj or file_obj.name == current_file_state:
428
- return gr.update(), gr.update(), current_file_state
429
  try:
430
- with open(file_obj.name, 'rb') as f:
431
- csv_content = f.read().decode('utf-8')
432
- df = pd.read_csv(io.StringIO(csv_content))
433
- df['timestamp'] = pd.to_datetime(df['timestamp'], errors='coerce')
434
-
435
  lab_site_options = ['All'] + [site for site in df['lab_site'].dropna().astype(str).unique().tolist() if site.strip()] if 'lab_site' in df.columns else ['All']
436
  equipment_type_options = ['All'] + [equip for equip in df['equipment_type'].dropna().astype(str).unique().tolist() if equip.strip()] if 'equipment_type' in df.columns else ['All']
437
-
438
- return gr.update(choices=lab_site_options, value='All'), gr.update(choices=equipment_type_options, value='All'), file_obj.name
439
  except Exception as e:
440
  logging.error(f"Failed to update filters: {str(e)}")
441
- return gr.update(choices=['All'], value='All'), gr.update(choices=['All'], value='All'), current_file_state
442
 
443
  # Gradio Interface
444
  try:
@@ -456,12 +455,12 @@ try:
456
  .table tr:nth-child(even) {background-color: #f9f9f9;}
457
  """) as iface:
458
  gr.Markdown("<h1>LabOps Log Analyzer Dashboard</h1>")
459
- gr.Markdown("Upload a CSV file to analyze. Click 'Analyze' to refresh the dashboard. Use 'Export PDF' for report download.")
460
 
461
  last_modified_state = gr.State(value=None)
462
- current_file_state = gr.State(value=None)
463
  cached_df_state = gr.State(value=None)
464
  cached_filtered_df_state = gr.State(value=None)
 
465
 
466
  with gr.Row():
467
  with gr.Column(scale=1):
@@ -511,17 +510,43 @@ try:
511
  gr.Markdown("### Export Report")
512
  pdf_output = gr.File(label="Download Status Report as PDF")
513
 
 
514
  file_input.change(
 
 
 
 
 
515
  fn=update_filters,
516
- inputs=[file_input, current_file_state],
517
- outputs=[lab_site_filter, equipment_type_filter, current_file_state],
518
  queue=False
519
  )
520
 
 
521
  submit_button.click(
522
  fn=process_logs,
523
- inputs=[file_input, lab_site_filter, equipment_type_filter, date_range_filter, last_modified_state, cached_df_state, cached_filtered_df_state],
524
- outputs=[summary_output, preview_output, usage_chart_output, device_cards_output, daily_log_trends_output, weekly_uptime_output, anomaly_alerts_output, downtime_chart_output, anomaly_output, amc_output, insights_output, pdf_output, last_modified_state, cached_df_state, cached_filtered_df_state]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
  )
526
 
527
  pdf_button.click(
 
5
  import plotly.express as px
6
  import plotly.graph_objects as go
7
  from sklearn.ensemble import IsolationForest
8
+ from concurrent.futures import ThreadPoolExecutor
9
  import os
10
  import io
11
  import time
 
315
  return None
316
 
317
  # Main processing function
318
+ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_range, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path):
319
  start_time = time.time()
320
  try:
321
+ if not file_obj and not current_file_path:
322
+ return "No file uploaded.", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, "No anomalies detected.", "No AMC reminders.", "No insights generated.", None, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path
323
 
324
+ file_path = file_obj.name if file_obj else current_file_path
325
+ current_modified_time = os.path.getmtime(file_path) if os.path.exists(file_path) else 0
326
+
327
+ # Check if we can use cached filtered data
328
+ if (last_modified_state == current_modified_time and
329
+ cached_filtered_df_state is not None and
330
+ file_path == current_file_path):
331
  filtered_df = cached_filtered_df_state
332
  else:
333
+ if cached_df_state is None or current_modified_time != last_modified_state or file_path != current_file_path:
334
  logging.info(f"Processing file: {file_path}")
335
  if not file_path.endswith(".csv"):
336
+ return "Please upload a CSV file.", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, "", "", "", None, last_modified_state, cached_df_state, cached_filtered_df_state, file_path
337
 
338
  required_columns = ["device_id", "log_type", "status", "timestamp", "usage_hours", "downtime", "amc_date"]
339
  dtypes = {
 
347
  df = pd.read_csv(file_path, dtype=dtypes)
348
  missing_columns = [col for col in required_columns if col not in df.columns]
349
  if missing_columns:
350
+ return f"Missing columns: {missing_columns}", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, None, None, None, None, last_modified_state, cached_df_state, cached_filtered_df_state, file_path
351
 
352
  df["timestamp"] = pd.to_datetime(df["timestamp"], errors='coerce')
353
  df["amc_date"] = pd.to_datetime(df["amc_date"], errors='coerce')
354
  if df["timestamp"].dt.tz is None:
355
  df["timestamp"] = df["timestamp"].dt.tz_localize('UTC').dt.tz_convert('Asia/Kolkata')
356
  if df.empty:
357
+ return "No data available.", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, None, None, None, None, last_modified_state, df, cached_filtered_df_state, file_path
358
  else:
359
  df = cached_df_state
360
 
 
372
  filtered_df = filtered_df[(filtered_df['timestamp'] >= start_date) & (filtered_df['timestamp'] <= end_date)]
373
 
374
  if filtered_df.empty:
375
+ return "No data after applying filters.", pd.DataFrame(), None, '<p>No device cards available.</p>', None, None, None, None, None, None, None, None, last_modified_state, df, filtered_df, file_path
376
 
377
  # Generate table for preview
378
  preview_df = filtered_df[['device_id', 'log_type', 'status', 'timestamp', 'usage_hours', 'downtime', 'amc_date']].head(5)
 
411
  if elapsed_time > 3:
412
  logging.warning(f"Processing time exceeded 3 seconds: {elapsed_time:.2f} seconds")
413
 
414
+ return (summary, preview_html, usage_chart, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, anomalies, amc_reminders, insights, None, current_modified_time, df, filtered_df, file_path)
415
  except Exception as e:
416
  logging.error(f"Failed to process file: {str(e)}")
417
+ return f"Error: {str(e)}", pd.DataFrame(), None, '<p>Error processing data.</p>', None, None, None, None, None, None, None, None, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path
418
 
419
  # Generate PDF separately
420
  async def generate_pdf(summary, preview_html, usage_chart, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, anomalies, amc_reminders, insights):
 
427
  return None
428
 
429
  # Update filters
430
+ def update_filters(file_path, cached_df_state):
431
+ if not file_path or not cached_df_state:
432
+ return gr.update(choices=['All'], value='All'), gr.update(choices=['All'], value='All')
433
  try:
434
+ df = cached_df_state
 
 
 
 
435
  lab_site_options = ['All'] + [site for site in df['lab_site'].dropna().astype(str).unique().tolist() if site.strip()] if 'lab_site' in df.columns else ['All']
436
  equipment_type_options = ['All'] + [equip for equip in df['equipment_type'].dropna().astype(str).unique().tolist() if equip.strip()] if 'equipment_type' in df.columns else ['All']
437
+ return gr.update(choices=lab_site_options, value='All'), gr.update(choices=equipment_type_options, value='All')
 
438
  except Exception as e:
439
  logging.error(f"Failed to update filters: {str(e)}")
440
+ return gr.update(choices=['All'], value='All'), gr.update(choices=['All'], value='All')
441
 
442
  # Gradio Interface
443
  try:
 
455
  .table tr:nth-child(even) {background-color: #f9f9f9;}
456
  """) as iface:
457
  gr.Markdown("<h1>LabOps Log Analyzer Dashboard</h1>")
458
+ gr.Markdown("Upload a CSV file to analyze. Click 'Analyze' to refresh the dashboard. Use 'Export PDF' for report download. Filters update without re-uploading the CSV.")
459
 
460
  last_modified_state = gr.State(value=None)
 
461
  cached_df_state = gr.State(value=None)
462
  cached_filtered_df_state = gr.State(value=None)
463
+ current_file_path = gr.State(value=None)
464
 
465
  with gr.Row():
466
  with gr.Column(scale=1):
 
510
  gr.Markdown("### Export Report")
511
  pdf_output = gr.File(label="Download Status Report as PDF")
512
 
513
+ # Update filters when CSV is uploaded
514
  file_input.change(
515
+ fn=lambda file_obj, cached_df, file_path: (file_obj.name if file_obj else file_path, cached_df, file_path),
516
+ inputs=[file_input, cached_df_state, current_file_path],
517
+ outputs=[current_file_path, cached_df_state, current_file_path],
518
+ queue=False
519
+ ).then(
520
  fn=update_filters,
521
+ inputs=[current_file_path, cached_df_state],
522
+ outputs=[lab_site_filter, equipment_type_filter],
523
  queue=False
524
  )
525
 
526
+ # Process logs on submit or filter change
527
  submit_button.click(
528
  fn=process_logs,
529
+ inputs=[file_input, lab_site_filter, equipment_type_filter, date_range_filter, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path],
530
+ outputs=[summary_output, preview_output, usage_chart_output, device_cards_output, daily_log_trends_output, weekly_uptime_output, anomaly_alerts_output, downtime_chart_output, anomaly_output, amc_output, insights_output, pdf_output, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path]
531
+ )
532
+
533
+ # Update on filter change without requiring new file
534
+ lab_site_filter.change(
535
+ fn=process_logs,
536
+ inputs=[file_input, lab_site_filter, equipment_type_filter, date_range_filter, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path],
537
+ outputs=[summary_output, preview_output, usage_chart_output, device_cards_output, daily_log_trends_output, weekly_uptime_output, anomaly_alerts_output, downtime_chart_output, anomaly_output, amc_output, insights_output, pdf_output, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path]
538
+ )
539
+
540
+ equipment_type_filter.change(
541
+ fn=process_logs,
542
+ inputs=[file_input, lab_site_filter, equipment_type_filter, date_range_filter, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path],
543
+ outputs=[summary_output, preview_output, usage_chart_output, device_cards_output, daily_log_trends_output, weekly_uptime_output, anomaly_alerts_output, downtime_chart_output, anomaly_output, amc_output, insights_output, pdf_output, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path]
544
+ )
545
+
546
+ date_range_filter.change(
547
+ fn=process_logs,
548
+ inputs=[file_input, lab_site_filter, equipment_type_filter, date_range_filter, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path],
549
+ outputs=[summary_output, preview_output, usage_chart_output, device_cards_output, daily_log_trends_output, weekly_uptime_output, anomaly_alerts_output, downtime_chart_output, anomaly_output, amc_output, insights_output, pdf_output, last_modified_state, cached_df_state, cached_filtered_df_state, current_file_path]
550
  )
551
 
552
  pdf_button.click(