RathodHarish commited on
Commit
25ba827
·
verified ·
1 Parent(s): 3f22e01

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -50
app.py CHANGED
@@ -12,35 +12,36 @@ 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:
18
- from reportlab.lib.pagesizes import letter
19
- from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
20
- from reportlab.lib.styles import getSampleStyleSheet
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
@@ -57,30 +58,125 @@ 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...")
86
  try:
@@ -94,13 +190,13 @@ def summarize_logs(df, progress=gr.Progress()):
94
  logging.error(f"Summary generation failed: {str(e)}")
95
  return f"Failed to generate summary: {str(e)}"
96
 
97
- # Anomaly Detection using Isolation Forest
98
  def detect_anomalies(df, progress=gr.Progress()):
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)
@@ -119,7 +215,7 @@ def detect_anomalies(df, progress=gr.Progress()):
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:
@@ -139,7 +235,7 @@ def check_amc_reminders(df, current_date, progress=gr.Progress()):
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:
@@ -152,7 +248,7 @@ def generate_dashboard_insights(df, progress=gr.Progress()):
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:
@@ -194,32 +290,26 @@ def generate_pdf_content(summary, preview, anomalies, amc_reminders, insights):
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
 
@@ -231,19 +321,18 @@ def generate_pdf_content(summary, preview, anomalies, amc_reminders, insights):
231
  return None
232
 
233
  # Main Gradio function
234
- async def process_logs(file_obj, progress=gr.Progress()):
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",
@@ -256,26 +345,27 @@ async def process_logs(file_obj, progress=gr.Progress()):
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(
@@ -286,17 +376,15 @@ async def process_logs(file_obj, progress=gr.Progress()):
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:
@@ -310,7 +398,7 @@ try:
310
  .dashboard-section ul {margin: 2px 0; padding-left: 20px;}
311
  """) as iface:
312
  gr.Markdown("<h1>LabOps Log Analyzer Dashboard (Hugging Face AI)</h1>")
313
- gr.Markdown("Upload a CSV file containing lab equipment logs to analyze.")
314
 
315
  with gr.Row():
316
  with gr.Column(scale=1):
@@ -319,7 +407,7 @@ try:
319
 
320
  with gr.Column(scale=2):
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")
@@ -349,6 +437,10 @@ try:
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")
@@ -364,7 +456,8 @@ try:
364
  amc_output,
365
  insights_output,
366
  pdf_output,
367
- salesforce_output
 
368
  ]
369
  )
370
 
 
12
  from concurrent.futures import ThreadPoolExecutor
13
  from simple_salesforce import Salesforce
14
  import os
15
+ import json
 
 
 
 
 
 
 
 
 
 
16
 
17
  # Configure logging
18
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
19
 
20
+ # Salesforce configuration
21
  try:
22
  sf = Salesforce(
23
  username=os.getenv('SF_USERNAME'),
24
  password=os.getenv('SF_PASSWORD'),
25
  security_token=os.getenv('SF_SECURITY_TOKEN'),
26
+ domain='login'
27
  )
28
  logging.info("Salesforce connection established")
29
  except Exception as e:
30
  logging.error(f"Failed to connect to Salesforce: {str(e)}")
31
  sf = None
32
 
33
+ # Try to import reportlab
34
+ try:
35
+ from reportlab.lib.pagesizes import letter
36
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
37
+ from reportlab.lib.styles import getSampleStyleSheet
38
+ reportlab_available = True
39
+ logging.info("reportlab module successfully imported")
40
+ except ImportError:
41
+ logging.warning("reportlab module not found. PDF generation disabled.")
42
+ reportlab_available = False
43
+
44
+ # Preload Hugging Face model
45
  logging.info("Preloading Hugging Face model...")
46
  try:
47
  device = 0 if torch.cuda.is_available() else -1
 
58
  logging.error(f"Failed to preload model: {str(e)}")
59
  raise e
60
 
61
+ # Fetch valid picklist values from Salesforce
62
+ def get_picklist_values(field_name):
63
+ if sf is None:
64
+ return []
65
+ try:
66
+ obj_desc = sf.SmartLog__c.describe()
67
+ for field in obj_desc['fields']:
68
+ if field['name'] == field_name:
69
+ return [value['value'] for value in field['picklistValues'] if value['active']]
70
+ return []
71
+ except Exception as e:
72
+ logging.error(f"Failed to fetch picklist values for {field_name}: {str(e)}")
73
+ return []
74
+
75
+ # Cache picklist values at startup
76
+ status_values = get_picklist_values('Status__c') or ["Active", "Inactive", "Pending"]
77
+ log_type_values = get_picklist_values('Log_Type__c') or ["Smart Log", "Cell Analysis", "UV Verification"]
78
+ logging.info(f"Valid Status__c values: {status_values}")
79
+ logging.info(f"Valid Log_Type__c values: {log_type_values}")
80
+
81
+ # Map invalid picklist values to valid ones
82
+ picklist_mapping = {
83
+ 'Status__c': {
84
+ 'normal': 'Active',
85
+ 'error': 'Inactive',
86
+ 'warning': 'Pending',
87
+ 'ok': 'Active',
88
+ 'failed': 'Inactive'
89
+ },
90
+ 'Log_Type__c': {
91
+ 'maint': 'Smart Log',
92
+ 'error': 'Cell Analysis',
93
+ 'ops': 'UV Verification',
94
+ 'maintenance': 'Smart Log',
95
+ 'cell': 'Cell Analysis',
96
+ 'uv': 'UV Verification'
97
+ }
98
+ }
99
+
100
+ # Create Salesforce report
101
+ def create_salesforce_report(df):
102
+ if sf is None:
103
+ return "Salesforce connection not available."
104
+ try:
105
+ report_metadata = {
106
+ "reportMetadata": {
107
+ "name": f"SmartLog_Usage_Report_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
108
+ "reportType": {"type": "SmartLog__c"},
109
+ "reportFormat": "SUMMARY",
110
+ "reportBooleanFilter": "",
111
+ "reportFilters": [
112
+ {"column": "Status__c", "operator": "equals", "value": "Active"}
113
+ ],
114
+ "reportColumns": [
115
+ {"column": "Device_Id__c"},
116
+ {"column": "Log_Type__c"},
117
+ {"column": "Status__c"},
118
+ {"column": "Timestamp__c"},
119
+ {"column": "Usage_Hours__c", "aggregate": "Sum"},
120
+ {"column": "Downtime__c", "aggregate": "Sum"},
121
+ {"column": "AMC_Date__c"}
122
+ ],
123
+ "groupingsDown": [{"name": "Device_Id__c", "sortOrder": "Asc"}],
124
+ "folderName": "LabOps Reports"
125
+ }
126
+ }
127
+ result = sf.restful('analytics/reports', method='POST', json=report_metadata)
128
+ logging.info(f"Report created: {result['id']}")
129
+ return result['id']
130
+ except Exception as e:
131
+ logging.error(f"Failed to create Salesforce report: {str(e)}")
132
+ return None
133
+
134
+ # Save results to Salesforce SmartLog__c
135
  def save_to_salesforce(df, summary, anomalies, amc_reminders, insights):
136
  if sf is None:
 
137
  return "Salesforce connection not available."
138
  try:
139
+ records = []
140
+ for _, row in df.head(100).iterrows():
141
+ # Validate and map picklist values
142
+ status = str(row['status'])
143
+ log_type = str(row['log_type'])
144
+
145
+ # Map Status__c
146
+ if status not in status_values:
147
+ status = picklist_mapping['Status__c'].get(status.lower(), status_values[0] if status_values else None)
148
+ if status is None:
149
+ logging.warning(f"Skipping record with invalid Status__c: {row['status']}")
150
+ continue
151
+
152
+ # Map Log_Type__c
153
+ if log_type not in log_type_values:
154
+ log_type = picklist_mapping['Log_Type__c'].get(log_type.lower(), log_type_values[0] if log_type_values else None)
155
+ if log_type is None:
156
+ logging.warning(f"Skipping record with invalid Log_Type__c: {row['log_type']}")
157
+ continue
158
+
159
  record = {
160
  'Device_Id__c': str(row['device_id'])[:50],
161
+ 'Log_Type__c': log_type,
162
+ 'Status__c': status,
163
  'Timestamp__c': row['timestamp'].isoformat() if pd.notna(row['timestamp']) else None,
164
  'Usage_Hours__c': float(row['usage_hours']) if pd.notna(row['usage_hours']) else 0.0,
165
  'Downtime__c': float(row['downtime']) if pd.notna(row['downtime']) else 0.0,
166
  'AMC_Date__c': row['amc_date'].strftime('%Y-%m-%d') if pd.notna(row['amc_date']) else None
167
  }
168
+ records.append(record)
169
+
170
+ # Bulk insert to reduce API calls
171
+ if records:
172
+ sf.bulk.SmartLog__c.insert(records)
173
+ logging.info(f"Saved {len(records)} records to Salesforce")
174
+ return f"Saved {len(records)} records to Salesforce."
175
  except Exception as e:
176
  logging.error(f"Failed to save to Salesforce: {str(e)}")
177
  return f"Failed to save to Salesforce: {str(e)}"
178
 
179
+ # Summarize logs
180
  def summarize_logs(df, progress=gr.Progress()):
181
  progress(0.1, "Generating summary report...")
182
  try:
 
190
  logging.error(f"Summary generation failed: {str(e)}")
191
  return f"Failed to generate summary: {str(e)}"
192
 
193
+ # Anomaly detection
194
  def detect_anomalies(df, progress=gr.Progress()):
195
  progress(0.4, "Detecting anomalies...")
196
  try:
197
  if "usage_hours" not in df.columns or "downtime" not in df.columns:
198
  return "Anomaly detection requires 'usage_hours' and 'downtime' columns."
199
+ if len(df) > 1000:
200
  df = df.sample(n=1000, random_state=42)
201
  features = df[["usage_hours", "downtime"]].fillna(0)
202
  iso_forest = IsolationForest(contamination=0.1, random_state=42, n_jobs=-1)
 
215
  logging.error(f"Anomaly detection failed: {str(e)}")
216
  return f"Anomaly detection failed: {str(e)}"
217
 
218
+ # AMC reminders
219
  def check_amc_reminders(df, current_date, progress=gr.Progress()):
220
  progress(0.6, "Checking AMC reminders...")
221
  try:
 
235
  logging.error(f"AMC reminder generation failed: {str(e)}")
236
  return f"AMC reminder generation failed: {str(e)}"
237
 
238
+ # Dashboard insights
239
  def generate_dashboard_insights(df, progress=gr.Progress()):
240
  progress(0.8, "Generating dashboard insights...")
241
  try:
 
248
  logging.error(f"Dashboard insights generation failed: {str(e)}")
249
  return f"Dashboard insights generation failed: {str(e)}"
250
 
251
+ # Create usage chart
252
  def create_usage_chart(df, progress=gr.Progress()):
253
  progress(0.9, "Creating usage chart...")
254
  try:
 
290
  def safe_paragraph(text, style):
291
  return Paragraph(str(text).replace('\n', '<br/>'), style) if text else Paragraph("", style)
292
 
 
293
  story.append(Paragraph("LabOps Log Analysis Report", styles['Title']))
294
  story.append(Paragraph(f"Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", styles['Normal']))
295
  story.append(Spacer(1, 12))
296
 
 
297
  story.append(Paragraph("Summary Report", styles['Heading2']))
298
  story.append(safe_paragraph(summary or "No summary available.", styles['Normal']))
299
  story.append(Spacer(1, 12))
300
 
 
301
  story.append(Paragraph("Log Preview", styles['Heading2']))
302
  story.append(safe_paragraph(preview or "No preview available.", styles['Normal']))
303
  story.append(Spacer(1, 12))
304
 
 
305
  story.append(Paragraph("Anomaly Detection", styles['Heading2']))
306
  story.append(safe_paragraph(anomalies or "No anomalies detected.", styles['Normal']))
307
  story.append(Spacer(1, 12))
308
 
 
309
  story.append(Paragraph("AMC Reminders", styles['Heading2']))
310
  story.append(safe_paragraph(amc_reminders or "No AMC reminders.", styles['Normal']))
311
  story.append(Spacer(1, 12))
312
 
 
313
  story.append(Paragraph("Dashboard Insights", styles['Heading2']))
314
  story.append(safe_paragraph(insights or "No insights generated.", styles['Normal']))
315
 
 
321
  return None
322
 
323
  # Main Gradio function
324
+ async def process_logs(file_obj, progress правилайлаProgress()):
325
  try:
326
  progress(0, "Starting file processing...")
327
  if not file_obj:
328
+ return "No file uploaded.", "No data to preview.", None, "No anomalies detected.", "No AMC reminders.", "No insights generated.", None, "No Salesforce data saved.", "No report created."
329
 
330
  file_name = file_obj.name
331
  logging.info(f"Processing file: {file_name}")
332
 
333
  if not file_name.endswith(".csv"):
334
+ return "Please upload a CSV file.", "", None, "", "", "", None, "", ""
335
 
 
336
  required_columns = ["device_id", "log_type", "status", "timestamp", "usage_hours", "downtime", "amc_date"]
337
  dtypes = {
338
  "device_id": "string",
 
345
  df = pd.read_csv(file_obj, dtype=dtypes)
346
  missing_columns = [col for col in required_columns if col not in df.columns]
347
  if missing_columns:
348
+ return f"Missing columns: {missing_columns}", None, None, None, None, None, None, None, None
349
  df["timestamp"] = pd.to_datetime(df["timestamp"], errors='coerce')
350
+ df["amc_date"] = pd.to_datetime(df["amc_date"], errors='coerce')
351
  if df.empty:
352
+ return "No data available.", None, None, None, None, None, None, None, None
353
 
 
354
  with ThreadPoolExecutor() as executor:
355
  future_summary = executor.submit(summarize_logs, df)
356
  future_anomalies = executor.submit(detect_anomalies, df)
357
  future_amc = executor.submit(check_amc_reminders, df, datetime.now())
358
  future_insights = executor.submit(generate_dashboard_insights, df)
359
  future_chart = executor.submit(create_usage_chart, df)
360
+ future_report = executor.submit(create_salesforce_report, df)
361
 
362
  summary = f"Step 1: Summary Report\n{future_summary.result()}"
363
  anomalies = f"Anomaly Detection\n{future_anomalies.result()}"
364
  amc_reminders = f"AMC Reminders\n{future_amc.result()}"
365
  insights = f"Dashboard Insights (AI)\n{future_insights.result()}"
366
  chart = future_chart.result()
367
+ report_id = future_report.result()
368
 
 
369
  preview_lines = ["Step 2: Log Preview (First 5 Rows)"]
370
  for idx, row in df.head(5).iterrows():
371
  preview_lines.append(
 
376
  )
377
  preview = "\n".join(preview_lines)
378
 
 
379
  salesforce_result = save_to_salesforce(df, summary, anomalies, amc_reminders, insights)
 
 
380
  pdf_file = generate_pdf_content(summary, preview, anomalies, amc_reminders, insights)
381
+ report_result = f"Report created in Salesforce with ID: {report_id}" if report_id else "Failed to create report."
382
 
383
  progress(1.0, "Done!")
384
+ return summary, preview, chart, anomalies, amc_reminders, insights, pdf_file, salesforce_result, report_result
385
  except Exception as e:
386
  logging.error(f"Failed to process file: {str(e)}")
387
+ return f"Error: {str(e)}", None, None, None, None, None, None, None, None
388
 
389
  # Gradio Interface
390
  try:
 
398
  .dashboard-section ul {margin: 2px 0; padding-left: 20px;}
399
  """) as iface:
400
  gr.Markdown("<h1>LabOps Log Analyzer Dashboard (Hugging Face AI)</h1>")
401
+ gr.Markdown("Upload a CSV file to analyze and generate Salesforce reports.")
402
 
403
  with gr.Row():
404
  with gr.Column(scale=1):
 
407
 
408
  with gr.Column(scale=2):
409
  with gr.Group(elem_classes="dashboard-container"):
410
+ gr.Markdown("<div class='dashboard-title'>Analysis Results</div>")
411
 
412
  with gr.Group(elem_classes="dashboard-section"):
413
  gr.Markdown("### Step 1: Summary Report")
 
437
  gr.Markdown("### Salesforce Integration")
438
  salesforce_output = gr.Markdown()
439
 
440
+ with gr.Group(elem_classes="dashboard-section"):
441
+ gr.Markdown("### Salesforce Report")
442
+ report_output = gr.Markdown()
443
+
444
  with gr.Group(elem_classes="dashboard-section"):
445
  gr.Markdown("### Download Report")
446
  pdf_output = gr.File(label="Download Analysis Report as PDF")
 
456
  amc_output,
457
  insights_output,
458
  pdf_output,
459
+ salesforce_output,
460
+ report_output
461
  ]
462
  )
463