RathodHarish commited on
Commit
7a4c424
·
verified ·
1 Parent(s): 6ad3673

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +108 -138
app.py CHANGED
@@ -18,19 +18,6 @@ import functools
18
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
19
 
20
  # Salesforce configuration (Disabled for now)
21
- """
22
- try:
23
- sf = Salesforce(
24
- username='multi-devicelabopsdashboard@sathkrutha.com',
25
- password='Team@1234',
26
- security_token=os.getenv('SF_SECURITY_TOKEN', ''),
27
- domain='login'
28
- )
29
- logging.info("Salesforce connection established")
30
- except Exception as e:
31
- logging.error(f"Failed to connect to Salesforce: {str(e)}")
32
- sf = None
33
- """
34
  sf = None # Temporarily disable Salesforce
35
 
36
  # Try to import reportlab
@@ -53,9 +40,9 @@ try:
53
  "summarization",
54
  model="t5-small",
55
  device=device,
56
- max_length=30, # Reduced for faster inference
57
  min_length=10,
58
- num_beams=1 # Reduced for faster inference
59
  )
60
  logging.info(f"Hugging Face model preloaded on {'GPU' if device == 0 else 'CPU'}")
61
  except Exception as e:
@@ -125,111 +112,11 @@ LABOPS_REPORTS_FOLDER_ID = get_folder_id('LabOps Reports')
125
  def create_salesforce_reports(df):
126
  logging.info("Salesforce report creation skipped for optimization")
127
  return
128
- """
129
- def create_salesforce_reports(df):
130
- if sf is None or not LABOPS_REPORTS_FOLDER_ID:
131
- return
132
- try:
133
- timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
134
- reports = [
135
- {
136
- "reportMetadata": {
137
- "name": f"SmartLog_Usage_Report_{timestamp}",
138
- "developerName": f"SmartLog_Usage_Report_{timestamp}",
139
- "reportType": {"type": "CustomEntity", "value": "SmartLog__c"},
140
- "reportFormat": "TABULAR",
141
- "reportBooleanFilter": None,
142
- "reportFilters": [],
143
- "detailColumns": ["SmartLog__c.Device_Id__c", "SmartLog__c.Usage_Hours__c"],
144
- "folderId": LABOPS_REPORTS_FOLDER_ID
145
- }
146
- },
147
- {
148
- "reportMetadata": {
149
- "name": f"SmartLog_AMC_Reminders_{timestamp}",
150
- "developerName": f"SmartLog_AMC_Reminders_{timestamp}",
151
- "reportType": {"type": "CustomEntity", "value": "SmartLog__c"},
152
- "reportFormat": "TABULAR",
153
- "reportBooleanFilter": None,
154
- "reportFilters": [],
155
- "detailColumns": ["SmartLog__c.Device_Id__c", "SmartLog__c.AMC_Date__c"],
156
- "folderId": LABOPS_REPORTS_FOLDER_ID
157
- }
158
- }
159
- ]
160
- for report in reports:
161
- sf.restful('analytics/reports', method='POST', json=report)
162
- logging.info("Salesforce reports created")
163
- except Exception as e:
164
- logging.error(f"Failed to create Salesforce reports: {str(e)}")
165
- """
166
 
167
  # Save to Salesforce (Disabled for now)
168
  def save_to_salesforce(df, reminders_df):
169
  logging.info("Salesforce save operation skipped for optimization")
170
  return
171
- """
172
- def save_to_salesforce(df, reminders_df):
173
- if sf is None:
174
- logging.error("No Salesforce connection available")
175
- return
176
- try:
177
- logging.info("Starting Salesforce save operation")
178
- current_date = datetime.now()
179
- next_30_days = current_date + timedelta(days=30)
180
- records = []
181
- reminder_device_ids = set(reminders_df['device_id']) if not reminders_df.empty else set()
182
- logging.info(f"Processing {len(df)} records for Salesforce")
183
-
184
- for idx, row in df.iterrows():
185
- status = str(row['status']).lower()
186
- log_type = str(row['log_type']).lower()
187
- status_mapped = picklist_mapping['Status__c'].get(status, status_values[0] if status_values else 'Active')
188
- log_type_mapped = picklist_mapping['Log_Type__c'].get(log_type, log_type_values[0] if log_type_values else 'Smart Log')
189
-
190
- if not status_mapped or not log_type_mapped:
191
- logging.warning(f"Skipping record {idx}: Invalid status ({status}) or log_type ({log_type})")
192
- continue
193
-
194
- amc_date_str = None
195
- if pd.notna(row['amc_date']):
196
- try:
197
- amc_date = pd.to_datetime(row['amc_date']).strftime('%Y-%m-%d')
198
- amc_date_str = amc_date
199
- amc_date_dt = datetime.strptime(amc_date, '%Y-%m-%d')
200
- if status_mapped == "Active" and current_date.date() <= amc_date_dt.date() <= next_30_days.date():
201
- logging.info(f"AMC Reminder for Device ID {row['device_id']}: {amc_date}")
202
- except Exception as e:
203
- logging.warning(f"Invalid AMC date for Device ID {row['device_id']}: {str(e)}")
204
-
205
- record = {
206
- 'Device_Id__c': str(row['device_id'])[:50],
207
- 'Log_Type__c': log_type_mapped,
208
- 'Status__c': status_mapped,
209
- 'Timestamp__c': row['timestamp'].isoformat() if pd.notna(row['timestamp']) else None,
210
- 'Usage_Hours__c': float(row['usage_hours']) if pd.notna(row['usage_hours']) else 0.0,
211
- 'Downtime__c': float(row['downtime']) if pd.notna(row['downtime']) else 0.0,
212
- 'AMC_Date__c': amc_date_str
213
- }
214
- records.append(record)
215
-
216
- if records:
217
- batch_size = 100
218
- for i in range(0, len(records), batch_size):
219
- batch = records[i:i + batch_size]
220
- try:
221
- result = sf.bulk.SmartLog__c.insert(batch)
222
- logging.info(f"Saved {len(batch)} records to Salesforce in batch {i//batch_size + 1}")
223
- for res in result:
224
- if not res['success']:
225
- logging.error(f"Failed to save record: {res['errors']}")
226
- except Exception as e:
227
- logging.error(f"Failed to save batch {i//batch_size + 1}: {str(e)}")
228
- else:
229
- logging.warning("No records to save to Salesforce")
230
- except Exception as e:
231
- logging.error(f"Failed to save to Salesforce: {str(e)}")
232
- """
233
 
234
  # Cache summarization results
235
  def cache_summary(func):
@@ -267,9 +154,9 @@ def detect_anomalies(df):
267
  if "usage_hours" not in df.columns or "downtime" not in df.columns:
268
  return "Anomaly detection requires 'usage_hours' and 'downtime' columns.", pd.DataFrame()
269
  features = df[["usage_hours", "downtime"]].fillna(0)
270
- if len(features) > 100: # Further reduced sample size
271
  features = features.sample(n=100, random_state=42)
272
- iso_forest = IsolationForest(contamination=0.1, random_state=42, n_estimators=30) # Further reduced n_estimators
273
  df["anomaly"] = iso_forest.fit_predict(features)
274
  anomalies = df[df["anomaly"] == -1][["device_id", "usage_hours", "downtime", "timestamp"]]
275
  if anomalies.empty:
@@ -329,7 +216,7 @@ def cache_dataframe(func):
329
  return result
330
  return wrapper
331
 
332
- # Create usage chart (Only this chart will be generated to save time)
333
  @cache_dataframe
334
  def create_usage_chart(df):
335
  try:
@@ -351,18 +238,102 @@ def create_usage_chart(df):
351
  logging.error(f"Failed to create usage chart: {str(e)}")
352
  return None
353
 
354
- # Skipped other chart functions to save time
 
355
  def create_downtime_chart(df):
356
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
 
 
 
358
  def create_daily_log_trends_chart(df):
359
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
 
 
 
361
  def create_weekly_uptime_chart(df):
362
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
 
 
 
364
  def create_anomaly_alerts_chart(anomalies_df):
365
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
366
 
367
  # Generate device cards
368
  def generate_device_cards(df):
@@ -397,7 +368,7 @@ def generate_device_cards(df):
397
  logging.error(f"Failed to generate device cards: {str(e)}")
398
  return f'<p>Error generating device cards: {str(e)}</p>'
399
 
400
- # Generate PDF content (Simplified to reduce time)
401
  def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards_html):
402
  if not reportlab_available:
403
  return None
@@ -470,7 +441,7 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
470
  progress(0, desc="Starting processing...")
471
  try:
472
  if not file_obj:
473
- 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
474
 
475
  file_path = file_obj.name
476
  current_modified_time = os.path.getmtime(file_path)
@@ -492,7 +463,7 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
492
  "amc_date": "string"
493
  }
494
  df = pd.read_csv(file_path, dtype=dtypes, usecols=required_columns)
495
- if len(df) > 5000: # More aggressive sampling
496
  df = df.sample(n=5000, random_state=42)
497
  logging.warning("Dataset too large, sampled to 5,000 rows")
498
 
@@ -531,12 +502,15 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
531
 
532
  # Run tasks concurrently
533
  progress(0.4, desc="Running analysis tasks...")
534
- with ThreadPoolExecutor(max_workers=4) as executor: # Reduced workers to avoid overhead
535
  future_summary = executor.submit(summarize_logs, filtered_df)
536
  future_anomalies = executor.submit(detect_anomalies, filtered_df)
537
  future_amc = executor.submit(check_amc_reminders, filtered_df, datetime.now())
538
  future_insights = executor.submit(generate_dashboard_insights, filtered_df)
539
  future_usage_chart = executor.submit(create_usage_chart, filtered_df)
 
 
 
540
  future_device_cards = executor.submit(generate_device_cards, filtered_df)
541
 
542
  progress(0.5, desc="Collecting summary results...")
@@ -549,25 +523,21 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
549
  amc_reminders = f"AMC Reminders\n{amc_reminders}"
550
  progress(0.8, desc="Collecting insights...")
551
  insights = f"Dashboard Insights (AI)\n{future_insights.result()}"
552
- progress(0.9, desc="Generating chart...")
553
  usage_chart = future_usage_chart.result()
554
- downtime_chart = None
555
- daily_log_chart = None
556
- weekly_uptime_chart = None
557
- anomaly_alerts_chart = None
558
  device_cards = future_device_cards.result()
559
 
560
- # Skip Salesforce operations
561
- # save_to_salesforce(filtered_df, reminders_df)
562
- # create_salesforce_reports(filtered_df)
563
-
564
  progress(0.95, desc="Generating PDF...")
565
  pdf_file = generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards)
566
 
567
  elapsed_time = time.time() - start_time
568
  logging.info(f"Processing completed in {elapsed_time:.2f} seconds")
569
- if elapsed_time > 10:
570
- logging.warning(f"Processing time exceeded 10 seconds: {elapsed_time:.2f} seconds")
571
 
572
  progress(1.0, desc="Processing complete!")
573
  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)
 
18
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
19
 
20
  # Salesforce configuration (Disabled for now)
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  sf = None # Temporarily disable Salesforce
22
 
23
  # Try to import reportlab
 
40
  "summarization",
41
  model="t5-small",
42
  device=device,
43
+ max_length=30,
44
  min_length=10,
45
+ num_beams=1
46
  )
47
  logging.info(f"Hugging Face model preloaded on {'GPU' if device == 0 else 'CPU'}")
48
  except Exception as e:
 
112
  def create_salesforce_reports(df):
113
  logging.info("Salesforce report creation skipped for optimization")
114
  return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  # Save to Salesforce (Disabled for now)
117
  def save_to_salesforce(df, reminders_df):
118
  logging.info("Salesforce save operation skipped for optimization")
119
  return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
  # Cache summarization results
122
  def cache_summary(func):
 
154
  if "usage_hours" not in df.columns or "downtime" not in df.columns:
155
  return "Anomaly detection requires 'usage_hours' and 'downtime' columns.", pd.DataFrame()
156
  features = df[["usage_hours", "downtime"]].fillna(0)
157
+ if len(features) > 100:
158
  features = features.sample(n=100, random_state=42)
159
+ iso_forest = IsolationForest(contamination=0.1, random_state=42, n_estimators=30)
160
  df["anomaly"] = iso_forest.fit_predict(features)
161
  anomalies = df[df["anomaly"] == -1][["device_id", "usage_hours", "downtime", "timestamp"]]
162
  if anomalies.empty:
 
216
  return result
217
  return wrapper
218
 
219
+ # Create usage chart
220
  @cache_dataframe
221
  def create_usage_chart(df):
222
  try:
 
238
  logging.error(f"Failed to create usage chart: {str(e)}")
239
  return None
240
 
241
+ # Create downtime chart (Re-enabled with optimization)
242
+ @cache_dataframe
243
  def create_downtime_chart(df):
244
+ try:
245
+ if df.empty:
246
+ return None
247
+ downtime_data = df.groupby("device_id")["downtime"].sum().reset_index()
248
+ if len(downtime_data) > 5:
249
+ downtime_data = downtime_data.nlargest(5, "downtime")
250
+ fig = px.bar(
251
+ downtime_data,
252
+ x="device_id",
253
+ y="downtime",
254
+ title="Downtime per Device",
255
+ labels={"device_id": "Device ID", "downtime": "Downtime (Hours)"}
256
+ )
257
+ fig.update_layout(title_font_size=16, margin=dict(l=20, r=20, t=40, b=20))
258
+ return fig
259
+ except Exception as e:
260
+ logging.error(f"Failed to create downtime chart: {str(e)}")
261
+ return None
262
 
263
+ # Create daily log trends chart (Re-enabled with optimization)
264
+ @cache_dataframe
265
  def create_daily_log_trends_chart(df):
266
+ try:
267
+ if df.empty:
268
+ return None
269
+ df['date'] = df['timestamp'].dt.date
270
+ daily_logs = df.groupby('date').size().reset_index(name='log_count')
271
+ if len(daily_logs) > 30: # Limit to 30 days for faster plotting
272
+ daily_logs = daily_logs.tail(30)
273
+ fig = px.line(
274
+ daily_logs,
275
+ x='date',
276
+ y='log_count',
277
+ title="Daily Log Trends",
278
+ labels={"date": "Date", "log_count": "Number of Logs"}
279
+ )
280
+ fig.update_layout(title_font_size=16, margin=dict(l=20, r=20, t=40, b=20))
281
+ return fig
282
+ except Exception as e:
283
+ logging.error(f"Failed to create daily log trends chart: {str(e)}")
284
+ return None
285
 
286
+ # Create weekly uptime chart (Re-enabled with optimization)
287
+ @cache_dataframe
288
  def create_weekly_uptime_chart(df):
289
+ try:
290
+ if df.empty:
291
+ return None
292
+ df['week'] = df['timestamp'].dt.isocalendar().week
293
+ df['year'] = df['timestamp'].dt.year
294
+ weekly_data = df.groupby(['year', 'week']).agg({
295
+ 'usage_hours': 'sum',
296
+ 'downtime': 'sum'
297
+ }).reset_index()
298
+ if len(weekly_data) > 12: # Limit to 12 weeks for faster plotting
299
+ weekly_data = weekly_data.tail(12)
300
+ weekly_data['uptime_percent'] = (weekly_data['usage_hours'] / (weekly_data['usage_hours'] + weekly_data['downtime'])) * 100
301
+ weekly_data['year_week'] = weekly_data['year'].astype(str) + '-W' + weekly_data['week'].astype(str)
302
+ fig = px.bar(
303
+ weekly_data,
304
+ x='year_week',
305
+ y='uptime_percent',
306
+ title="Weekly Uptime Percentage",
307
+ labels={"year_week": "Year-Week", "uptime_percent": "Uptime %"}
308
+ )
309
+ fig.update_layout(title_font_size=16, margin=dict(l=20, r=20, t=40, b=20))
310
+ return fig
311
+ except Exception as e:
312
+ logging.error(f"Failed to create weekly uptime chart: {str(e)}")
313
+ return None
314
 
315
+ # Create anomaly alerts chart (Re-enabled with optimization)
316
+ @cache_dataframe
317
  def create_anomaly_alerts_chart(anomalies_df):
318
+ try:
319
+ if anomalies_df.empty:
320
+ return None
321
+ anomalies_df['date'] = anomalies_df['timestamp'].dt.date
322
+ anomaly_counts = anomalies_df.groupby('date').size().reset_index(name='anomaly_count')
323
+ if len(anomaly_counts) > 30: # Limit to 30 days for faster plotting
324
+ anomaly_counts = anomaly_counts.tail(30)
325
+ fig = px.scatter(
326
+ anomaly_counts,
327
+ x='date',
328
+ y='anomaly_count',
329
+ title="Anomaly Alerts Over Time",
330
+ labels={"date": "Date", "anomaly_count": "Number of Anomalies"}
331
+ )
332
+ fig.update_layout(title_font_size=16, margin=dict(l=20, r=20, t=40, b=20))
333
+ return fig
334
+ except Exception as e:
335
+ logging.error(f"Failed to create anomaly alerts chart: {str(e)}")
336
+ return None
337
 
338
  # Generate device cards
339
  def generate_device_cards(df):
 
368
  logging.error(f"Failed to generate device cards: {str(e)}")
369
  return f'<p>Error generating device cards: {str(e)}</p>'
370
 
371
+ # Generate PDF content
372
  def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards_html):
373
  if not reportlab_available:
374
  return None
 
441
  progress(0, desc="Starting processing...")
442
  try:
443
  if not file_obj:
444
+ return "No file uploaded.", pd.DataFrame(), None, '<p>No device cardsPEM available.</p>', None, None, None, None, "No anomalies detected.", "No AMC reminders.", "No insights generated.", None, last_modified_state
445
 
446
  file_path = file_obj.name
447
  current_modified_time = os.path.getmtime(file_path)
 
463
  "amc_date": "string"
464
  }
465
  df = pd.read_csv(file_path, dtype=dtypes, usecols=required_columns)
466
+ if len(df) > 5000:
467
  df = df.sample(n=5000, random_state=42)
468
  logging.warning("Dataset too large, sampled to 5,000 rows")
469
 
 
502
 
503
  # Run tasks concurrently
504
  progress(0.4, desc="Running analysis tasks...")
505
+ with ThreadPoolExecutor(max_workers=4) as executor:
506
  future_summary = executor.submit(summarize_logs, filtered_df)
507
  future_anomalies = executor.submit(detect_anomalies, filtered_df)
508
  future_amc = executor.submit(check_amc_reminders, filtered_df, datetime.now())
509
  future_insights = executor.submit(generate_dashboard_insights, filtered_df)
510
  future_usage_chart = executor.submit(create_usage_chart, filtered_df)
511
+ future_downtime_chart = executor.submit(create_downtime_chart, filtered_df)
512
+ future_daily_log_chart = executor.submit(create_daily_log_trends_chart, filtered_df)
513
+ future_weekly_uptime_chart = executor.submit(create_weekly_uptime_chart, filtered_df)
514
  future_device_cards = executor.submit(generate_device_cards, filtered_df)
515
 
516
  progress(0.5, desc="Collecting summary results...")
 
523
  amc_reminders = f"AMC Reminders\n{amc_reminders}"
524
  progress(0.8, desc="Collecting insights...")
525
  insights = f"Dashboard Insights (AI)\n{future_insights.result()}"
526
+ progress(0.9, desc="Generating charts...")
527
  usage_chart = future_usage_chart.result()
528
+ downtime_chart = future_downtime_chart.result()
529
+ daily_log_chart = future_daily_log_chart.result()
530
+ weekly_uptime_chart = future_weekly_uptime_chart.result()
531
+ anomaly_alerts_chart = create_anomaly_alerts_chart(anomalies_df)
532
  device_cards = future_device_cards.result()
533
 
 
 
 
 
534
  progress(0.95, desc="Generating PDF...")
535
  pdf_file = generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards)
536
 
537
  elapsed_time = time.time() - start_time
538
  logging.info(f"Processing completed in {elapsed_time:.2f} seconds")
539
+ if elapsed_time > 30:
540
+ logging.warning(f"Processing time exceeded 30 seconds: {elapsed_time:.2f} seconds")
541
 
542
  progress(1.0, desc="Processing complete!")
543
  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)