RathodHarish commited on
Commit
03bf5d9
·
verified ·
1 Parent(s): 1e2e9c7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +144 -129
app.py CHANGED
@@ -1,5 +1,5 @@
1
  """
2
- LabOps Log Analyzer Dashboard with CSV file upload and optional PDF generation
3
  """
4
  import gradio as gr
5
  import pandas as pd
@@ -9,6 +9,9 @@ import plotly.express as px
9
  from sklearn.ensemble import IsolationForest
10
  from transformers import pipeline
11
  import torch
 
 
 
12
 
13
  # Try to import reportlab for PDF generation
14
  try:
@@ -18,22 +21,65 @@ try:
18
  reportlab_available = True
19
  logging.info("reportlab module successfully imported")
20
  except ImportError:
21
- logging.warning("reportlab module not found. PDF generation will be disabled. Install with: pip install reportlab")
22
  reportlab_available = False
23
 
24
- # Configure logging for debugging
25
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
26
 
27
- # Preload Hugging Face summarization model at startup
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  logging.info("Preloading Hugging Face model...")
29
  try:
30
  device = 0 if torch.cuda.is_available() else -1
31
- summarizer = pipeline("summarization", model="sshleifer/distilbart-cnn-12-6", device=device)
32
- logging.info(f"Hugging Face model preloaded successfully on device: {'GPU' if device == 0 else 'CPU'}")
 
 
 
 
 
 
 
33
  except Exception as e:
34
  logging.error(f"Failed to preload model: {str(e)}")
35
  raise e
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  # Format summary prompt and generate report
38
  def summarize_logs(df, progress=gr.Progress()):
39
  progress(0.1, "Generating summary report...")
@@ -53,11 +99,9 @@ def detect_anomalies(df, progress=gr.Progress()):
53
  progress(0.4, "Detecting anomalies...")
54
  try:
55
  if "usage_hours" not in df.columns or "downtime" not in df.columns:
56
- logging.warning("Required columns for anomaly detection not found")
57
  return "Anomaly detection requires 'usage_hours' and 'downtime' columns."
58
- if len(df) > 5000:
59
- df = df.sample(n=5000, random_state=42)
60
- logging.info("Sampled data for anomaly detection to 5,000 rows")
61
  features = df[["usage_hours", "downtime"]].fillna(0)
62
  iso_forest = IsolationForest(contamination=0.1, random_state=42, n_jobs=-1)
63
  df["anomaly"] = iso_forest.fit_predict(features)
@@ -65,21 +109,21 @@ def detect_anomalies(df, progress=gr.Progress()):
65
  if anomalies.empty:
66
  return "No anomalies detected."
67
  anomaly_lines = ["Detected Anomalies:"]
68
- for idx, row in anomalies.head(5).iterrows():
69
- anomaly_lines.append(f"- Device ID: {row['device_id']}, Usage Hours: {row['usage_hours']}, Downtime: {row['downtime']}, Timestamp: {row['timestamp']}")
70
- anomaly_list = "\n".join(anomaly_lines)
71
- logging.info("Anomalies detected successfully")
72
- return anomaly_list
 
73
  except Exception as e:
74
  logging.error(f"Anomaly detection failed: {str(e)}")
75
  return f"Anomaly detection failed: {str(e)}"
76
 
77
- # AMC Reminders based on device and AMC date
78
  def check_amc_reminders(df, current_date, progress=gr.Progress()):
79
  progress(0.6, "Checking AMC reminders...")
80
  try:
81
  if "device_id" not in df.columns or "amc_date" not in df.columns:
82
- logging.warning("Required columns for AMC reminders not found")
83
  return "AMC reminders require 'device_id' and 'amc_date' columns."
84
  df["amc_date"] = pd.to_datetime(df["amc_date"], errors='coerce')
85
  current_date = pd.to_datetime(current_date)
@@ -88,16 +132,14 @@ def check_amc_reminders(df, current_date, progress=gr.Progress()):
88
  if reminders.empty:
89
  return "No AMC reminders due within the next 30 days."
90
  reminder_lines = ["Upcoming AMC Reminders:"]
91
- for idx, row in reminders.head(5).iterrows():
92
  reminder_lines.append(f"- Device ID: {row['device_id']}, AMC Date: {row['amc_date']}")
93
- reminder_list = "\n".join(reminder_lines)
94
- logging.info("AMC reminders generated successfully")
95
- return reminder_list
96
  except Exception as e:
97
  logging.error(f"AMC reminder generation failed: {str(e)}")
98
  return f"AMC reminder generation failed: {str(e)}"
99
 
100
- # Dashboard Insights (AI-generated)
101
  def generate_dashboard_insights(df, progress=gr.Progress()):
102
  progress(0.8, "Generating dashboard insights...")
103
  try:
@@ -105,20 +147,18 @@ def generate_dashboard_insights(df, progress=gr.Progress()):
105
  avg_usage = df["usage_hours"].mean() if "usage_hours" in df.columns else 0
106
  prompt = f"Insights: {total_devices} devices, avg usage {avg_usage:.2f} hours."
107
  insights = summarizer(prompt, max_length=50, min_length=10, do_sample=False)[0]["summary_text"]
108
- logging.info("Dashboard insights generated successfully")
109
  return insights
110
  except Exception as e:
111
  logging.error(f"Dashboard insights generation failed: {str(e)}")
112
  return f"Dashboard insights generation failed: {str(e)}"
113
 
114
- # Create a bar chart for usage hours per device
115
  def create_usage_chart(df, progress=gr.Progress()):
116
  progress(0.9, "Creating usage chart...")
117
  try:
118
  usage_data = df.groupby("device_id")["usage_hours"].sum().reset_index()
119
  if len(usage_data) > 5:
120
  usage_data = usage_data.nlargest(5, "usage_hours")
121
- logging.info("Limited chart data to top 5 devices")
122
  custom_colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']
123
  fig = px.bar(
124
  usage_data,
@@ -141,54 +181,50 @@ def create_usage_chart(df, progress=gr.Progress()):
141
  logging.error(f"Failed to create usage chart: {str(e)}")
142
  return None
143
 
144
- # Generate PDF content using reportlab if available
145
  def generate_pdf_content(summary, preview, anomalies, amc_reminders, insights):
146
  if not reportlab_available:
147
- logging.warning("Skipping PDF generation: reportlab not installed")
148
  return None
149
  try:
150
- pdf_path = "analysis_report.pdf"
151
  doc = SimpleDocTemplate(pdf_path, pagesize=letter)
152
  styles = getSampleStyleSheet()
153
  story = []
154
 
 
 
 
155
  # Title
156
  story.append(Paragraph("LabOps Log Analysis Report", styles['Title']))
157
- story.append(Paragraph(f"Generated on {datetime.now().strftime('%Y-%m-%d')}", styles['Normal']))
158
  story.append(Spacer(1, 12))
159
 
160
  # Summary Report
161
  story.append(Paragraph("Summary Report", styles['Heading2']))
162
- for line in summary.split('\n'):
163
- story.append(Paragraph(line, styles['Normal']))
164
  story.append(Spacer(1, 12))
165
 
166
  # Log Preview
167
  story.append(Paragraph("Log Preview", styles['Heading2']))
168
- for line in preview.split('\n'):
169
- story.append(Paragraph(line, styles['Normal']))
170
  story.append(Spacer(1, 12))
171
 
172
  # Anomaly Detection
173
  story.append(Paragraph("Anomaly Detection", styles['Heading2']))
174
- for line in anomalies.split('\n'):
175
- story.append(Paragraph(line, styles['Normal']))
176
  story.append(Spacer(1, 12))
177
 
178
  # AMC Reminders
179
  story.append(Paragraph("AMC Reminders", styles['Heading2']))
180
- for line in amc_reminders.split('\n'):
181
- story.append(Paragraph(line, styles['Normal']))
182
  story.append(Spacer(1, 12))
183
 
184
  # Dashboard Insights
185
  story.append(Paragraph("Dashboard Insights", styles['Heading2']))
186
- for line in insights.split('\n'):
187
- story.append(Paragraph(line, styles['Normal']))
188
 
189
- # Build PDF
190
  doc.build(story)
191
- logging.info(f"PDF generated successfully at {pdf_path}")
192
  return pdf_path
193
  except Exception as e:
194
  logging.error(f"Failed to generate PDF: {str(e)}")
@@ -199,95 +235,68 @@ async def process_logs(file_obj, progress=gr.Progress()):
199
  try:
200
  progress(0, "Starting file processing...")
201
  if not file_obj:
202
- logging.warning("No file uploaded, returning empty results")
203
- return "No file uploaded.", "No data to preview.", None, "No anomalies detected.", "No AMC reminders.", "No insights generated.", None
204
 
205
  file_name = file_obj.name
206
  logging.info(f"Processing file: {file_name}")
207
 
208
  if not file_name.endswith(".csv"):
209
- logging.error("Unsupported file format")
210
- return "Unsupported file format. Please upload a CSV file.", "", None, "", "", "", None
211
-
212
- try:
213
- required_columns = ["device_id", "log_type", "status", "timestamp", "usage_hours", "downtime", "amc_date"]
214
- dtypes = {
215
- "device_id": "string",
216
- "log_type": "string",
217
- "status": "string",
218
- "usage_hours": "float32",
219
- "downtime": "float32",
220
- "amc_date": "string"
221
- }
222
- df = pd.read_csv(file_obj, dtype=dtypes)
223
- # Check for required columns
224
- missing_columns = [col for col in required_columns if col not in df.columns]
225
- if missing_columns:
226
- logging.error(f"Missing columns: {missing_columns}")
227
- return f"Missing required columns: {missing_columns}", None, None, None, None, None, None
228
- logging.info(f"File loaded successfully with {len(df)} rows")
229
- except Exception as e:
230
- logging.error(f"Failed to load CSV: {str(e)}")
231
- return f"Failed to load CSV: {str(e)}", None, None, None, None, None, None
232
-
233
- try:
234
- df["timestamp"] = pd.to_datetime(df["timestamp"], errors='coerce')
235
- except Exception as e:
236
- logging.error(f"Date conversion failed: {str(e)}")
237
- return f"Failed to convert timestamp to datetime: {str(e)}", None, None, None, None, None, None
238
-
239
  if df.empty:
240
- logging.warning("No data provided in the file")
241
- return "No data available in provided.", None, None, None, None, None, None
242
-
243
- # Step 1: Summary
244
- progress(0.2, "Summary...")
245
- summary = f"Step 1: Summary Report\n{summarize_logs(df)}"
246
-
247
- # Step 2: Log Preview
248
- progress(0.3, "Previewing...")
249
- if not df.empty:
250
- preview_lines = ["Step 2: Log Preview (First 5 Rows)"]
251
- for idx, row in df.head(5).iterrows():
252
- preview_lines.append(
253
- f"Row {idx + 1}: Device ID: {row['device_id']}, "
254
- f"Log Type: {row['log_type']}, Status: {row['status']}, "
255
- f"Timestamp: {row['timestamp']}, Usage Hours: {row['usage_hours']}, "
256
- f"Downtime: {row['downtime']}, AMC Date: {row['amc_date']}"
257
- )
258
- preview = "\n".join(preview_lines)
259
- else:
260
- preview = "Step 2: Log Preview\nNo data available."
261
-
262
- # Step 3: Usage Chart
263
- progress(0.5, "Chart...")
264
- chart = create_usage_chart(df)
265
-
266
- # Step 4: Anomaly Detection
267
- progress(0.7, "Anomalies...")
268
- anomalies = f"Anomaly Detection\n{detect_anomalies(df)}"
269
-
270
- # Step 5: AMC Reminders
271
- progress(0.8, "AMC...")
272
- amc_reminders = f"AMC Reminders\n{check_amc_reminders(df, datetime.now())}"
273
-
274
- # Step 6: Insights
275
- progress(0.9, "Insights...")
276
- insights = f"Dashboard Insights (AI)\n{generate_dashboard_insights(df)}"
277
-
278
- # Generate PDF if available
279
- progress(0.95, "PDF...")
280
- pdf_file = generate_pdf_content(summary, preview, anomalies, amc_reminders, insights) if reportlab_available else None
281
- if pdf_file is None and reportlab_available:
282
- logging.warning("PDF generation failed")
283
- elif pdf_file is None:
284
- logging.info("PDF skipped: no reportlab")
285
 
286
  progress(1.0, "Done!")
287
- return summary, preview, chart, anomalies, amc_reminders, insights, pdf_file
288
  except Exception as e:
289
  logging.error(f"Failed to process file: {str(e)}")
290
- return f"Error processing file: {str(e)}", None, None, None, None, None, None
291
 
292
  # Gradio Interface
293
  try:
@@ -312,37 +321,34 @@ try:
312
  with gr.Group(elem_classes="dashboard-container"):
313
  gr.Markdown("<div class='dashboard-title'>Analysis Results (Step-by-Step)</div>")
314
 
315
- # Step 1: Summary Report
316
  with gr.Group(elem_classes="dashboard-section"):
317
  gr.Markdown("### Step 1: Summary Report")
318
  summary_output = gr.Markdown()
319
 
320
- # Step 2: Log Preview
321
  with gr.Group(elem_classes="dashboard-section"):
322
  gr.Markdown("### Step 2: Log Preview")
323
  preview_output = gr.Markdown()
324
 
325
- # Step 3: Usage Chart
326
  with gr.Group(elem_classes="dashboard-section"):
327
  gr.Markdown("### Step 3: Usage Chart")
328
  chart_output = gr.Plot()
329
 
330
- # Step 4: Anomaly Detection
331
  with gr.Group(elem_classes="dashboard-section"):
332
  gr.Markdown("### Step 4: Anomaly Detection")
333
  anomaly_output = gr.Markdown()
334
 
335
- # Step 5: AMC Reminders
336
  with gr.Group(elem_classes="dashboard-section"):
337
  gr.Markdown("### Step 5: AMC Reminders")
338
  amc_output = gr.Markdown()
339
 
340
- # Step 6: Dashboard Insights
341
  with gr.Group(elem_classes="dashboard-section"):
342
  gr.Markdown("### Step 6: Insights (AI)")
343
  insights_output = gr.Markdown()
344
 
345
- # PDF Download
 
 
 
346
  with gr.Group(elem_classes="dashboard-section"):
347
  gr.Markdown("### Download Report")
348
  pdf_output = gr.File(label="Download Analysis Report as PDF")
@@ -350,7 +356,16 @@ try:
350
  submit_button.click(
351
  fn=process_logs,
352
  inputs=[file_input],
353
- outputs=[summary_output, preview_output, chart_output, anomaly_output, amc_output, insights_output, pdf_output]
 
 
 
 
 
 
 
 
 
354
  )
355
 
356
  logging.info("Gradio interface initialized successfully")
@@ -366,4 +381,4 @@ if __name__ == "__main__":
366
  except Exception as e:
367
  logging.error(f"Failed to launch Gradio interface: {str(e)}")
368
  print(f"Error launching app: {str(e)}")
369
- raise e
 
1
  """
2
+ LabOps Log Analyzer Dashboard with CSV file upload, PDF generation, and Salesforce integration
3
  """
4
  import gradio as gr
5
  import pandas as pd
 
9
  from sklearn.ensemble import IsolationForest
10
  from transformers import pipeline
11
  import torch
12
+ from concurrent.futures import ThreadPoolExecutor
13
+ from simple_salesforce import Salesforce
14
+ import os
15
 
16
  # Try to import reportlab for PDF generation
17
  try:
 
21
  reportlab_available = True
22
  logging.info("reportlab module successfully imported")
23
  except ImportError:
24
+ logging.warning("reportlab module not found. PDF generation will be disabled.")
25
  reportlab_available = False
26
 
27
+ # Configure logging
28
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
29
 
30
+ # Salesforce configuration (environment variables for security)
31
+ try:
32
+ sf = Salesforce(
33
+ username=os.getenv('SF_USERNAME'),
34
+ password=os.getenv('SF_PASSWORD'),
35
+ security_token=os.getenv('SF_SECURITY_TOKEN'),
36
+ domain='login' # Use 'test' for sandbox
37
+ )
38
+ logging.info("Salesforce connection established")
39
+ except Exception as e:
40
+ logging.error(f"Failed to connect to Salesforce: {str(e)}")
41
+ sf = None
42
+
43
+ # Preload Hugging Face summarization model
44
  logging.info("Preloading Hugging Face model...")
45
  try:
46
  device = 0 if torch.cuda.is_available() else -1
47
+ summarizer = pipeline(
48
+ "summarization",
49
+ model="facebook/bart-large-cnn",
50
+ device=device,
51
+ max_length=50,
52
+ min_length=10,
53
+ num_beams=4
54
+ )
55
+ logging.info(f"Hugging Face model preloaded on {'GPU' if device == 0 else 'CPU'}")
56
  except Exception as e:
57
  logging.error(f"Failed to preload model: {str(e)}")
58
  raise e
59
 
60
+ # Save results to Salesforce SmartLog__c object
61
+ def save_to_salesforce(df, summary, anomalies, amc_reminders, insights):
62
+ if sf is None:
63
+ logging.error("Salesforce connection not available")
64
+ return "Salesforce connection not available."
65
+ try:
66
+ for _, row in df.head(100).iterrows(): # Limit to 100 rows to avoid governor limits
67
+ record = {
68
+ 'Device_Id__c': str(row['device_id'])[:50],
69
+ 'Log_Type__c': str(row['log_type']),
70
+ 'Status__c': str(row['status']),
71
+ 'Timestamp__c': row['timestamp'].isoformat() if pd.notna(row['timestamp']) else None,
72
+ 'Usage_Hours__c': float(row['usage_hours']) if pd.notna(row['usage_hours']) else 0.0,
73
+ 'Downtime__c': float(row['downtime']) if pd.notna(row['downtime']) else 0.0,
74
+ 'AMC_Date__c': row['amc_date'].strftime('%Y-%m-%d') if pd.notna(row['amc_date']) else None
75
+ }
76
+ sf.SmartLog__c.create(record)
77
+ logging.info("Data saved to Salesforce successfully")
78
+ return "Data saved to Salesforce."
79
+ except Exception as e:
80
+ logging.error(f"Failed to save to Salesforce: {str(e)}")
81
+ return f"Failed to save to Salesforce: {str(e)}"
82
+
83
  # Format summary prompt and generate report
84
  def summarize_logs(df, progress=gr.Progress()):
85
  progress(0.1, "Generating summary report...")
 
99
  progress(0.4, "Detecting anomalies...")
100
  try:
101
  if "usage_hours" not in df.columns or "downtime" not in df.columns:
 
102
  return "Anomaly detection requires 'usage_hours' and 'downtime' columns."
103
+ if len(df) > 1000: # Reduced sample size for speed
104
+ df = df.sample(n=1000, random_state=42)
 
105
  features = df[["usage_hours", "downtime"]].fillna(0)
106
  iso_forest = IsolationForest(contamination=0.1, random_state=42, n_jobs=-1)
107
  df["anomaly"] = iso_forest.fit_predict(features)
 
109
  if anomalies.empty:
110
  return "No anomalies detected."
111
  anomaly_lines = ["Detected Anomalies:"]
112
+ for _, row in anomalies.head(5).iterrows():
113
+ anomaly_lines.append(
114
+ f"- Device ID: {row['device_id']}, Usage Hours: {row['usage_hours']}, "
115
+ f"Downtime: {row['downtime']}, Timestamp: {row['timestamp']}"
116
+ )
117
+ return "\n".join(anomaly_lines)
118
  except Exception as e:
119
  logging.error(f"Anomaly detection failed: {str(e)}")
120
  return f"Anomaly detection failed: {str(e)}"
121
 
122
+ # AMC Reminders
123
  def check_amc_reminders(df, current_date, progress=gr.Progress()):
124
  progress(0.6, "Checking AMC reminders...")
125
  try:
126
  if "device_id" not in df.columns or "amc_date" not in df.columns:
 
127
  return "AMC reminders require 'device_id' and 'amc_date' columns."
128
  df["amc_date"] = pd.to_datetime(df["amc_date"], errors='coerce')
129
  current_date = pd.to_datetime(current_date)
 
132
  if reminders.empty:
133
  return "No AMC reminders due within the next 30 days."
134
  reminder_lines = ["Upcoming AMC Reminders:"]
135
+ for _, row in reminders.head(5).iterrows():
136
  reminder_lines.append(f"- Device ID: {row['device_id']}, AMC Date: {row['amc_date']}")
137
+ return "\n".join(reminder_lines)
 
 
138
  except Exception as e:
139
  logging.error(f"AMC reminder generation failed: {str(e)}")
140
  return f"AMC reminder generation failed: {str(e)}"
141
 
142
+ # Dashboard Insights
143
  def generate_dashboard_insights(df, progress=gr.Progress()):
144
  progress(0.8, "Generating dashboard insights...")
145
  try:
 
147
  avg_usage = df["usage_hours"].mean() if "usage_hours" in df.columns else 0
148
  prompt = f"Insights: {total_devices} devices, avg usage {avg_usage:.2f} hours."
149
  insights = summarizer(prompt, max_length=50, min_length=10, do_sample=False)[0]["summary_text"]
 
150
  return insights
151
  except Exception as e:
152
  logging.error(f"Dashboard insights generation failed: {str(e)}")
153
  return f"Dashboard insights generation failed: {str(e)}"
154
 
155
+ # Create a bar chart
156
  def create_usage_chart(df, progress=gr.Progress()):
157
  progress(0.9, "Creating usage chart...")
158
  try:
159
  usage_data = df.groupby("device_id")["usage_hours"].sum().reset_index()
160
  if len(usage_data) > 5:
161
  usage_data = usage_data.nlargest(5, "usage_hours")
 
162
  custom_colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']
163
  fig = px.bar(
164
  usage_data,
 
181
  logging.error(f"Failed to create usage chart: {str(e)}")
182
  return None
183
 
184
+ # Generate PDF content
185
  def generate_pdf_content(summary, preview, anomalies, amc_reminders, insights):
186
  if not reportlab_available:
 
187
  return None
188
  try:
189
+ pdf_path = f"analysis_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
190
  doc = SimpleDocTemplate(pdf_path, pagesize=letter)
191
  styles = getSampleStyleSheet()
192
  story = []
193
 
194
+ def safe_paragraph(text, style):
195
+ return Paragraph(str(text).replace('\n', '<br/>'), style) if text else Paragraph("", style)
196
+
197
  # Title
198
  story.append(Paragraph("LabOps Log Analysis Report", styles['Title']))
199
+ story.append(Paragraph(f"Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", styles['Normal']))
200
  story.append(Spacer(1, 12))
201
 
202
  # Summary Report
203
  story.append(Paragraph("Summary Report", styles['Heading2']))
204
+ story.append(safe_paragraph(summary or "No summary available.", styles['Normal']))
 
205
  story.append(Spacer(1, 12))
206
 
207
  # Log Preview
208
  story.append(Paragraph("Log Preview", styles['Heading2']))
209
+ story.append(safe_paragraph(preview or "No preview available.", styles['Normal']))
 
210
  story.append(Spacer(1, 12))
211
 
212
  # Anomaly Detection
213
  story.append(Paragraph("Anomaly Detection", styles['Heading2']))
214
+ story.append(safe_paragraph(anomalies or "No anomalies detected.", styles['Normal']))
 
215
  story.append(Spacer(1, 12))
216
 
217
  # AMC Reminders
218
  story.append(Paragraph("AMC Reminders", styles['Heading2']))
219
+ story.append(safe_paragraph(amc_reminders or "No AMC reminders.", styles['Normal']))
 
220
  story.append(Spacer(1, 12))
221
 
222
  # Dashboard Insights
223
  story.append(Paragraph("Dashboard Insights", styles['Heading2']))
224
+ story.append(safe_paragraph(insights or "No insights generated.", styles['Normal']))
 
225
 
 
226
  doc.build(story)
227
+ logging.info(f"PDF generated at {pdf_path}")
228
  return pdf_path
229
  except Exception as e:
230
  logging.error(f"Failed to generate PDF: {str(e)}")
 
235
  try:
236
  progress(0, "Starting file processing...")
237
  if not file_obj:
238
+ return "No file uploaded.", "No data to preview.", None, "No anomalies detected.", "No AMC reminders.", "No insights generated.", None, "No Salesforce data saved."
 
239
 
240
  file_name = file_obj.name
241
  logging.info(f"Processing file: {file_name}")
242
 
243
  if not file_name.endswith(".csv"):
244
+ return "Please upload a CSV file.", "", None, "", "", "", None, ""
245
+
246
+ # Load CSV
247
+ required_columns = ["device_id", "log_type", "status", "timestamp", "usage_hours", "downtime", "amc_date"]
248
+ dtypes = {
249
+ "device_id": "string",
250
+ "log_type": "string",
251
+ "status": "string",
252
+ "usage_hours": "float32",
253
+ "downtime": "float32",
254
+ "amc_date": "string"
255
+ }
256
+ df = pd.read_csv(file_obj, dtype=dtypes)
257
+ missing_columns = [col for col in required_columns if col not in df.columns]
258
+ if missing_columns:
259
+ return f"Missing columns: {missing_columns}", None, None, None, None, None, None, None
260
+ df["timestamp"] = pd.to_datetime(df["timestamp"], errors='coerce')
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  if df.empty:
262
+ return "No data available.", None, None, None, None, None, None, None
263
+
264
+ # Parallel processing for speed
265
+ with ThreadPoolExecutor() as executor:
266
+ future_summary = executor.submit(summarize_logs, df)
267
+ future_anomalies = executor.submit(detect_anomalies, df)
268
+ future_amc = executor.submit(check_amc_reminders, df, datetime.now())
269
+ future_insights = executor.submit(generate_dashboard_insights, df)
270
+ future_chart = executor.submit(create_usage_chart, df)
271
+
272
+ summary = f"Step 1: Summary Report\n{future_summary.result()}"
273
+ anomalies = f"Anomaly Detection\n{future_anomalies.result()}"
274
+ amc_reminders = f"AMC Reminders\n{future_amc.result()}"
275
+ insights = f"Dashboard Insights (AI)\n{future_insights.result()}"
276
+ chart = future_chart.result()
277
+
278
+ # Log Preview
279
+ preview_lines = ["Step 2: Log Preview (First 5 Rows)"]
280
+ for idx, row in df.head(5).iterrows():
281
+ preview_lines.append(
282
+ f"Row {idx + 1}: Device ID: {row['device_id']}, "
283
+ f"Log Type: {row['log_type']}, Status: {row['status']}, "
284
+ f"Timestamp: {row['timestamp']}, Usage Hours: {row['usage_hours']}, "
285
+ f"Downtime: {row['downtime']}, AMC Date: {row['amc_date']}"
286
+ )
287
+ preview = "\n".join(preview_lines)
288
+
289
+ # Save to Salesforce
290
+ salesforce_result = save_to_salesforce(df, summary, anomalies, amc_reminders, insights)
291
+
292
+ # Generate PDF
293
+ pdf_file = generate_pdf_content(summary, preview, anomalies, amc_reminders, insights)
 
 
 
 
 
 
 
 
 
 
 
 
 
294
 
295
  progress(1.0, "Done!")
296
+ return summary, preview, chart, anomalies, amc_reminders, insights, pdf_file, salesforce_result
297
  except Exception as e:
298
  logging.error(f"Failed to process file: {str(e)}")
299
+ return f"Error processing file: {str(e)}", None, None, None, None, None, None, None
300
 
301
  # Gradio Interface
302
  try:
 
321
  with gr.Group(elem_classes="dashboard-container"):
322
  gr.Markdown("<div class='dashboard-title'>Analysis Results (Step-by-Step)</div>")
323
 
 
324
  with gr.Group(elem_classes="dashboard-section"):
325
  gr.Markdown("### Step 1: Summary Report")
326
  summary_output = gr.Markdown()
327
 
 
328
  with gr.Group(elem_classes="dashboard-section"):
329
  gr.Markdown("### Step 2: Log Preview")
330
  preview_output = gr.Markdown()
331
 
 
332
  with gr.Group(elem_classes="dashboard-section"):
333
  gr.Markdown("### Step 3: Usage Chart")
334
  chart_output = gr.Plot()
335
 
 
336
  with gr.Group(elem_classes="dashboard-section"):
337
  gr.Markdown("### Step 4: Anomaly Detection")
338
  anomaly_output = gr.Markdown()
339
 
 
340
  with gr.Group(elem_classes="dashboard-section"):
341
  gr.Markdown("### Step 5: AMC Reminders")
342
  amc_output = gr.Markdown()
343
 
 
344
  with gr.Group(elem_classes="dashboard-section"):
345
  gr.Markdown("### Step 6: Insights (AI)")
346
  insights_output = gr.Markdown()
347
 
348
+ with gr.Group(elem_classes="dashboard-section"):
349
+ gr.Markdown("### Salesforce Integration")
350
+ salesforce_output = gr.Markdown()
351
+
352
  with gr.Group(elem_classes="dashboard-section"):
353
  gr.Markdown("### Download Report")
354
  pdf_output = gr.File(label="Download Analysis Report as PDF")
 
356
  submit_button.click(
357
  fn=process_logs,
358
  inputs=[file_input],
359
+ outputs=[
360
+ summary_output,
361
+ preview_output,
362
+ chart_output,
363
+ anomaly_output,
364
+ amc_output,
365
+ insights_output,
366
+ pdf_output,
367
+ salesforce_output
368
+ ]
369
  )
370
 
371
  logging.info("Gradio interface initialized successfully")
 
381
  except Exception as e:
382
  logging.error(f"Failed to launch Gradio interface: {str(e)}")
383
  print(f"Error launching app: {str(e)}")
384
+ raise e