RathodHarish commited on
Commit
88f1133
·
verified ·
1 Parent(s): db18ade

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +23 -56
app.py CHANGED
@@ -11,6 +11,7 @@ from simple_salesforce import Salesforce
11
  import os
12
  import io
13
  import time
 
14
 
15
  # Configure logging
16
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -200,7 +201,7 @@ def save_to_salesforce(df, reminders_df):
200
  records.append(record)
201
 
202
  if records:
203
- batch_size = 200 # Smaller batch size for faster processing
204
  for i in range(0, len(records), batch_size):
205
  batch = records[i:i + batch_size]
206
  try:
@@ -237,9 +238,9 @@ def detect_anomalies(df):
237
  if "usage_hours" not in df.columns or "downtime" not in df.columns:
238
  return "Anomaly detection requires 'usage_hours' and 'downtime' columns.", pd.DataFrame()
239
  features = df[["usage_hours", "downtime"]].fillna(0)
240
- if len(features) > 500:
241
- features = features.sample(n=500, random_state=42)
242
- iso_forest = IsolationForest(contamination=0.1, random_state=42)
243
  df["anomaly"] = iso_forest.fit_predict(features)
244
  anomalies = df[df["anomaly"] == -1][["device_id", "usage_hours", "downtime", "timestamp"]]
245
  if anomalies.empty:
@@ -263,7 +264,7 @@ def check_amc_reminders(df, current_date):
263
  reminders = df[(df["days_to_amc"] >= 0) & (df["days_to_amc"] <= 30)][["device_id", "log_type", "status", "timestamp", "usage_hours", "downtime", "amc_date"]]
264
  if reminders.empty:
265
  return "No AMC reminders due within the next 30 days.", reminders
266
- result = "\n".join([f"- Device ID: {row['device_id']}, AMC Date: {row['amc_date']}" for _, row in reminders.head(5).iterrows()])
267
  logging.info(f"AMC reminders generation took {time.time() - start_time:.2f} seconds")
268
  return result, reminders
269
  except Exception as e:
@@ -419,32 +420,12 @@ def generate_device_cards(df):
419
  logging.error(f"Failed to generate device cards: {str(e)}")
420
  return f'<p>Error generating device cards: {str(e)}</p>'
421
 
422
- # Generate monthly status
423
- def generate_monthly_status(df, selected_month):
424
- try:
425
- total_devices = df['device_id'].nunique()
426
- total_usage_hours = df['usage_hours'].sum()
427
- total_downtime = df['downtime'].sum()
428
- avg_usage = total_usage_hours / total_devices if total_devices > 0 else 0
429
- avg_downtime = total_downtime / total_devices if total_devices > 0 else 0
430
- return f"""
431
- Monthly Status for {selected_month}:
432
- - Total Devices: {total_devices}
433
- - Total Usage Hours: {total_usage_hours:.2f}
434
- - Total Downtime Hours: {total_downtime:.2f}
435
- - Average Usage per Device: {avg_usage:.2f} hours
436
- - Average Downtime per Device: {avg_downtime:.2f} hours
437
- """
438
- except Exception as e:
439
- logging.error(f"Failed to generate monthly status: {str(e)}")
440
- return f"Failed to generate monthly status: {str(e)}"
441
-
442
  # Generate PDF content
443
- def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards_html, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, df, selected_month):
444
  if not reportlab_available:
445
  return None
446
  try:
447
- pdf_path = f"monthly_status_report_{selected_month.replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
448
  doc = SimpleDocTemplate(pdf_path, pagesize=letter)
449
  styles = getSampleStyleSheet()
450
  story = []
@@ -452,16 +433,10 @@ def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights
452
  def safe_paragraph(text, style):
453
  return Paragraph(str(text).replace('\n', '<br/>'), style) if text else Paragraph("", style)
454
 
455
- story.append(Paragraph("LabOps Monthly Status Report", styles['Title']))
456
  story.append(Paragraph(f"Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", styles['Normal']))
457
  story.append(Spacer(1, 12))
458
 
459
- if selected_month != "All":
460
- monthly_status = generate_monthly_status(df, selected_month)
461
- story.append(Paragraph("Monthly Status Summary", styles['Heading2']))
462
- story.append(safe_paragraph(monthly_status, styles['Normal']))
463
- story.append(Spacer(1, 12))
464
-
465
  story.append(Paragraph("Summary Report", styles['Heading2']))
466
  story.append(safe_paragraph(summary, styles['Normal']))
467
  story.append(Spacer(1, 12))
@@ -516,7 +491,7 @@ def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights
516
  return None
517
 
518
  # Main processing function
519
- async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_range, month_filter, last_modified_state):
520
  start_time = time.time()
521
  try:
522
  if not file_obj:
@@ -540,7 +515,7 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
540
  "downtime": "float32",
541
  "amc_date": "string"
542
  }
543
- df = pd.read_csv(file_path, dtype=dtypes)
544
  missing_columns = [col for col in required_columns if col not in df.columns]
545
  if missing_columns:
546
  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
@@ -564,12 +539,6 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
564
  start_date = today + pd.Timedelta(days=days_start)
565
  end_date = today + pd.Timedelta(days=days_end) + pd.Timedelta(days=1) - pd.Timedelta(seconds=1)
566
  filtered_df = filtered_df[(filtered_df['timestamp'] >= start_date) & (filtered_df['timestamp'] <= end_date)]
567
- if month_filter and month_filter != "All":
568
- selected_date = pd.to_datetime(month_filter, format="%B %Y")
569
- filtered_df = filtered_df[
570
- (filtered_df['timestamp'].dt.year == selected_date.year) &
571
- (filtered_df['timestamp'].dt.month == selected_date.month)
572
- ]
573
 
574
  if filtered_df.empty:
575
  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
@@ -579,7 +548,7 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
579
  preview_html = preview_df.to_html(index=False, classes='table table-striped', border=0)
580
 
581
  # Run tasks concurrently
582
- with ThreadPoolExecutor(max_workers=6) as executor:
583
  future_summary = executor.submit(summarize_logs, filtered_df)
584
  future_anomalies = executor.submit(detect_anomalies, filtered_df)
585
  future_amc = executor.submit(check_amc_reminders, filtered_df, datetime.now())
@@ -601,16 +570,16 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
601
  downtime_chart = future_downtime_chart.result()
602
  daily_log_chart = future_daily_log_chart.result()
603
  weekly_uptime_chart = future_weekly_uptime_chart.result()
604
- anomaly_alerts_chart = create_anomaly_alerts_chart(anomalies_df) # Use anomalies_df
605
  device_cards = future_device_cards.result()
606
 
607
  save_to_salesforce(filtered_df, reminders_df)
608
- pdf_file = generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, filtered_df, month_filter)
609
 
610
  elapsed_time = time.time() - start_time
611
  logging.info(f"Processing completed in {elapsed_time:.2f} seconds")
612
- if elapsed_time > 10:
613
- logging.warning(f"Processing time exceeded 10 seconds: {elapsed_time:.2f} seconds")
614
 
615
  return (summary, preview_html, usage_chart, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, anomalies, amc_reminders, insights, pdf_file, current_modified_time)
616
  except Exception as e:
@@ -620,7 +589,7 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
620
  # Update filters
621
  def update_filters(file_obj):
622
  if not file_obj:
623
- return gr.update(choices=['All'], value='All'), gr.update(choices=['All'], value='All'), gr.update(choices=['All'], value='All')
624
  try:
625
  with open(file_obj.name, 'rb') as f:
626
  csv_content = f.read().decode('utf-8')
@@ -629,12 +598,11 @@ def update_filters(file_obj):
629
 
630
  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']
631
  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']
632
- month_options = ['All'] + sorted(df['timestamp'].dt.strftime('%B %Y').dropna().unique().tolist()) if 'timestamp' in df.columns else ['All']
633
 
634
- return gr.update(choices=lab_site_options, value='All'), gr.update(choices=equipment_type_options, value='All'), gr.update(choices=month_options, value='All')
635
  except Exception as e:
636
  logging.error(f"Failed to update filters: {str(e)}")
637
- return gr.update(choices=['All'], value='All'), gr.update(choices=['All'], value='All'), gr.update(choices=['All'], value='All')
638
 
639
  # Gradio Interface
640
  try:
@@ -664,7 +632,6 @@ try:
664
  lab_site_filter = gr.Dropdown(label="Lab Site", choices=['All'], value='All', interactive=True)
665
  equipment_type_filter = gr.Dropdown(label="Equipment Type", choices=['All'], value='All', interactive=True)
666
  date_range_filter = gr.Slider(label="Date Range (Days from Today)", minimum=-365, maximum=0, step=1, value=[-30, 0])
667
- month_filter = gr.Dropdown(label="Select Month for Report", choices=['All'], value='All', interactive=True)
668
  submit_button = gr.Button("Analyze", variant="primary")
669
 
670
  with gr.Column(scale=2):
@@ -702,19 +669,19 @@ try:
702
  insights_output = gr.Markdown()
703
  with gr.Group(elem_classes="dashboard-section"):
704
  gr.Markdown("### Export Report")
705
- pdf_output = gr.File(label="Download Monthly Status Report as PDF")
706
 
707
  file_input.change(
708
  fn=update_filters,
709
  inputs=[file_input],
710
- outputs=[lab_site_filter, equipment_type_filter, month_filter],
711
  queue=False
712
  )
713
 
714
  submit_button.click(
715
  fn=process_logs,
716
- inputs=[file_input, lab_site_filter, equipment_type_filter, date_range_filter, month_filter, last_modified_state],
717
- 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]
718
  )
719
 
720
  logging.info("Gradio interface initialized successfully")
 
11
  import os
12
  import io
13
  import time
14
+ import uuid
15
 
16
  # Configure logging
17
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 
201
  records.append(record)
202
 
203
  if records:
204
+ batch_size = 100 # Reduced batch size for faster processing
205
  for i in range(0, len(records), batch_size):
206
  batch = records[i:i + batch_size]
207
  try:
 
238
  if "usage_hours" not in df.columns or "downtime" not in df.columns:
239
  return "Anomaly detection requires 'usage_hours' and 'downtime' columns.", pd.DataFrame()
240
  features = df[["usage_hours", "downtime"]].fillna(0)
241
+ if len(features) > 200: # Reduced sample size for faster processing
242
+ features = features.sample(n=200, random_state=42)
243
+ iso_forest = IsolationForest(contamination=0.1, random_state=42, n_estimators=50) # Reduced n_estimators
244
  df["anomaly"] = iso_forest.fit_predict(features)
245
  anomalies = df[df["anomaly"] == -1][["device_id", "usage_hours", "downtime", "timestamp"]]
246
  if anomalies.empty:
 
264
  reminders = df[(df["days_to_amc"] >= 0) & (df["days_to_amc"] <= 30)][["device_id", "log_type", "status", "timestamp", "usage_hours", "downtime", "amc_date"]]
265
  if reminders.empty:
266
  return "No AMC reminders due within the next 30 days.", reminders
267
+ result = "\n".join([f"- Device ID: {row['device_id']}, Log Type: {row['log_type']}, Status: {row['status']}, Usage: {row['usage_hours']}, Downtime: {row['downtime']}, AMC Date: {row['amc_date']}" for _, row in reminders.head(5).iterrows()])
268
  logging.info(f"AMC reminders generation took {time.time() - start_time:.2f} seconds")
269
  return result, reminders
270
  except Exception as e:
 
420
  logging.error(f"Failed to generate device cards: {str(e)}")
421
  return f'<p>Error generating device cards: {str(e)}</p>'
422
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
  # Generate PDF content
424
+ def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards_html, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart):
425
  if not reportlab_available:
426
  return None
427
  try:
428
+ pdf_path = f"status_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
429
  doc = SimpleDocTemplate(pdf_path, pagesize=letter)
430
  styles = getSampleStyleSheet()
431
  story = []
 
433
  def safe_paragraph(text, style):
434
  return Paragraph(str(text).replace('\n', '<br/>'), style) if text else Paragraph("", style)
435
 
436
+ story.append(Paragraph("LabOps Status Report", styles['Title']))
437
  story.append(Paragraph(f"Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", styles['Normal']))
438
  story.append(Spacer(1, 12))
439
 
 
 
 
 
 
 
440
  story.append(Paragraph("Summary Report", styles['Heading2']))
441
  story.append(safe_paragraph(summary, styles['Normal']))
442
  story.append(Spacer(1, 12))
 
491
  return None
492
 
493
  # Main processing function
494
+ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_range, last_modified_state):
495
  start_time = time.time()
496
  try:
497
  if not file_obj:
 
515
  "downtime": "float32",
516
  "amc_date": "string"
517
  }
518
+ df = pd.read_csv(file_path, dtype=dtypes, usecols=required_columns)
519
  missing_columns = [col for col in required_columns if col not in df.columns]
520
  if missing_columns:
521
  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
 
539
  start_date = today + pd.Timedelta(days=days_start)
540
  end_date = today + pd.Timedelta(days=days_end) + pd.Timedelta(days=1) - pd.Timedelta(seconds=1)
541
  filtered_df = filtered_df[(filtered_df['timestamp'] >= start_date) & (filtered_df['timestamp'] <= end_date)]
 
 
 
 
 
 
542
 
543
  if filtered_df.empty:
544
  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
 
548
  preview_html = preview_df.to_html(index=False, classes='table table-striped', border=0)
549
 
550
  # Run tasks concurrently
551
+ with ThreadPoolExecutor(max_workers=8) as executor: # Increased workers for better parallelization
552
  future_summary = executor.submit(summarize_logs, filtered_df)
553
  future_anomalies = executor.submit(detect_anomalies, filtered_df)
554
  future_amc = executor.submit(check_amc_reminders, filtered_df, datetime.now())
 
570
  downtime_chart = future_downtime_chart.result()
571
  daily_log_chart = future_daily_log_chart.result()
572
  weekly_uptime_chart = future_weekly_uptime_chart.result()
573
+ anomaly_alerts_chart = create_anomaly_alerts_chart(anomalies_df)
574
  device_cards = future_device_cards.result()
575
 
576
  save_to_salesforce(filtered_df, reminders_df)
577
+ pdf_file = generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart)
578
 
579
  elapsed_time = time.time() - start_time
580
  logging.info(f"Processing completed in {elapsed_time:.2f} seconds")
581
+ if elapsed_time > 30:
582
+ logging.warning(f"Processing time exceeded 30 seconds: {elapsed_time:.2f} seconds")
583
 
584
  return (summary, preview_html, usage_chart, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, anomalies, amc_reminders, insights, pdf_file, current_modified_time)
585
  except Exception as e:
 
589
  # Update filters
590
  def update_filters(file_obj):
591
  if not file_obj:
592
+ return gr.update(choices=['All'], value='All'), gr.update(choices=['All'], value='All')
593
  try:
594
  with open(file_obj.name, 'rb') as f:
595
  csv_content = f.read().decode('utf-8')
 
598
 
599
  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']
600
  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']
 
601
 
602
+ return gr.update(choices=lab_site_options, value='All'), gr.update(choices=equipment_type_options, value='All')
603
  except Exception as e:
604
  logging.error(f"Failed to update filters: {str(e)}")
605
+ return gr.update(choices=['All'], value='All'), gr.update(choices=['All'], value='All')
606
 
607
  # Gradio Interface
608
  try:
 
632
  lab_site_filter = gr.Dropdown(label="Lab Site", choices=['All'], value='All', interactive=True)
633
  equipment_type_filter = gr.Dropdown(label="Equipment Type", choices=['All'], value='All', interactive=True)
634
  date_range_filter = gr.Slider(label="Date Range (Days from Today)", minimum=-365, maximum=0, step=1, value=[-30, 0])
 
635
  submit_button = gr.Button("Analyze", variant="primary")
636
 
637
  with gr.Column(scale=2):
 
669
  insights_output = gr.Markdown()
670
  with gr.Group(elem_classes="dashboard-section"):
671
  gr.Markdown("### Export Report")
672
+ pdf_output = gr.File(label="Download Status Report as PDF")
673
 
674
  file_input.change(
675
  fn=update_filters,
676
  inputs=[file_input],
677
+ outputs=[lab_site_filter, equipment_type_filter],
678
  queue=False
679
  )
680
 
681
  submit_button.click(
682
  fn=process_logs,
683
+ inputs=[file_input, lab_site_filter, equipment_type_filter, date_range_filter, last_modified_state],
684
+ outputs=[summary_output, preview_output, usage_chart_output, device_cards_output, daily_log_trends_output, weekly_uptime_output, anomaly_alerts_chart, downtime_chart_output, anomaly_output, amc_output, insights_output, pdf_output, last_modified_state]
685
  )
686
 
687
  logging.info("Gradio interface initialized successfully")