lokesh341 commited on
Commit
2af0ca0
·
verified ·
1 Parent(s): 6695731

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +108 -54
app.py CHANGED
@@ -10,8 +10,8 @@ import requests
10
  from datetime import datetime
11
  from simple_salesforce import Salesforce
12
 
13
- # Set up logging to capture errors and debug information
14
- logging.basicConfig(level=logging.INFO)
15
  logger = logging.getLogger(__name__)
16
 
17
  app = Flask(__name__)
@@ -35,6 +35,12 @@ try:
35
  domain=SF_DOMAIN
36
  )
37
  logger.info("Successfully connected to Salesforce")
 
 
 
 
 
 
38
  except Exception as e:
39
  logger.error(f"Failed to connect to Salesforce: {str(e)}")
40
  raise ValueError("Failed to connect to Salesforce")
@@ -58,33 +64,41 @@ vendor_logs = []
58
  def fetch_vendor_logs_from_salesforce():
59
  """Fetch vendor logs from Salesforce to send to Hugging Face."""
60
  try:
 
 
 
 
 
 
61
  query = """
62
- SELECT Id, Vendor_Log_Id__c, Vendor_Id__c, Work_Details__c, Quality_Report__c,
63
  Incident_Log__c, Work_Completion_Date__c, Actual_Completion_Date__c,
64
  Vendor_Log_Name__c, Delay_Days__c, Project__c
65
  FROM Vendor_Log__c
66
- WHERE CreatedDate = THIS_MONTH
67
  """
68
  result = sf.query(query)
69
  logs = []
70
  for record in result['records']:
 
71
  log = VendorLog(
72
- vendorLogId=record['Vendor_Log_Id__c'],
73
- vendorId=record['Vendor_Id__c'],
74
- workDetails=record['Work_Details__c'],
75
- qualityReport=record['Quality_Report__c'],
76
- incidentLog=record['Incident_Log__c'],
77
- workCompletionDate=record['Work_Completion_Date__c'],
78
- actualCompletionDate=record['Actual_Completion_Date__c'],
79
- vendorLogName=record['Vendor_Log_Name__c'],
80
- delayDays=record['Delay_Days__c'],
81
- project=record['Project__c']
82
  )
83
  logs.append(log)
 
84
  return logs
85
  except Exception as e:
86
  logger.error(f"Error fetching vendor logs from Salesforce: {str(e)}")
87
- raise
88
 
89
  def calculate_scores_with_hugging_face(log: VendorLog):
90
  """Send data to Hugging Face and get scores (mocked for now)."""
@@ -100,6 +114,9 @@ def calculate_scores_with_hugging_face(log: VendorLog):
100
  # Mocked Hugging Face API call (replace with actual API call)
101
  # headers = {"Authorization": f"Bearer {HUGGING_FACE_API_TOKEN}"}
102
  # response = requests.post(HUGGING_FACE_API_URL, json=payload, headers=headers)
 
 
 
103
  # scores = response.json()
104
 
105
  # Mocked response for now
@@ -107,8 +124,8 @@ def calculate_scores_with_hugging_face(log: VendorLog):
107
  'qualityScore': float(log.qualityReport.replace('% quality', '')),
108
  'timelinessScore': 100.0 if log.delayDays <= 0 else 80.0 if log.delayDays <= 3 else 60.0 if log.delayDays <= 7 else 40.0,
109
  'safetyScore': {'None': 100.0, 'Low': 80.0, 'Minor': 80.0, 'Medium': 50.0, 'High': 20.0}.get(log.incidentLog, 100.0),
110
- 'communicationScore': 0.0, # Will be calculated below
111
- 'finalScore': 0.0 # Will be calculated below
112
  }
113
  scores['communicationScore'] = (scores['qualityScore'] * 0.33 + scores['timelinessScore'] * 0.33 + scores['safetyScore'] * 0.33)
114
  scores['finalScore'] = (scores['qualityScore'] + scores['timelinessScore'] + scores['safetyScore'] + scores['communicationScore']) / 4
@@ -117,6 +134,7 @@ def calculate_scores_with_hugging_face(log: VendorLog):
117
  for key in scores:
118
  scores[key] = round(scores[key], 2)
119
 
 
120
  return scores
121
  except Exception as e:
122
  logger.error(f"Error calculating scores with Hugging Face: {str(e)}")
@@ -148,11 +166,11 @@ def get_feedback(score: float, metric: str) -> str:
148
  return "Poor: Communication issues detected"
149
  except Exception as e:
150
  logger.error(f"Error generating feedback: {str(e)}")
151
- raise
152
 
153
  def generate_pdf(vendor_id: str, vendor_log_name: str, scores: dict):
154
  try:
155
- filename = f'report_{vendor_id}.pdf'
156
  c = canvas.Canvas(filename, pagesize=letter)
157
  c.setFont('Helvetica', 12)
158
  c.drawString(100, 750, 'Subcontractor Performance Report')
@@ -167,7 +185,13 @@ def generate_pdf(vendor_id: str, vendor_log_name: str, scores: dict):
167
 
168
  with open(filename, 'rb') as f:
169
  pdf_content = f.read()
170
- os.remove(filename)
 
 
 
 
 
 
171
  return pdf_content
172
  except Exception as e:
173
  logger.error(f"Error generating PDF: {str(e)}")
@@ -183,7 +207,7 @@ def determine_alert_flag(final_score: float, all_logs: list):
183
  return final_score == lowest_score
184
  except Exception as e:
185
  logger.error(f"Error determining alert flag: {str(e)}")
186
- raise
187
 
188
  @app.route('/score', methods=['POST'])
189
  def score_vendor():
@@ -191,11 +215,13 @@ def score_vendor():
191
  # Validate the Authorization header
192
  authorization = request.headers.get('Authorization')
193
  if not authorization:
 
194
  return jsonify({'error': 'Authorization header missing'}), 401
195
 
196
  # Parse the request data
197
  data = request.get_json()
198
  if not data:
 
199
  return jsonify({'error': 'Invalid request data'}), 400
200
 
201
  # Validate and create VendorLog instance
@@ -204,6 +230,7 @@ def score_vendor():
204
 
205
  # Validate Salesforce session
206
  if not sf.session_id:
 
207
  return jsonify({'error': 'Salesforce session invalid'}), 401
208
 
209
  # Calculate scores using Hugging Face
@@ -232,17 +259,17 @@ def score_vendor():
232
  'extracted': True
233
  })
234
 
235
- # Save scores and PDF to Salesforce (Subcontractor_Performance_Score__c object)
236
  try:
237
  sf.Subcontractor_Performance_Score__c.create({
238
- 'Vendor_ID__c': log.vendorId,
239
  'Month__c': datetime.now().strftime('%Y-%m-%d'),
240
  'Quality_Score__c': scores['qualityScore'],
241
  'Timeliness_Score__c': scores['timelinessScore'],
242
  'Safety_Score__c': scores['safetyScore'],
243
  'Communication_Score__c': scores['communicationScore'],
244
- 'Final_Score__c': scores['finalScore'], # Note: This may be a formula field in Salesforce
245
- 'Certification_URL__c': pdf_base64, # Store base64 PDF (or upload to Salesforce Files and store URL)
246
  'Alert_Flag__c': alert_flag
247
  })
248
  logger.info(f"Successfully saved scores to Salesforce for Vendor Log: {log.vendorLogId}")
@@ -270,27 +297,35 @@ def score_vendor():
270
  @app.route('/', methods=['GET'])
271
  def get_dashboard():
272
  try:
273
- # Fetch data from Salesforce (Subcontractor_Performance_Score__c)
274
  query = """
275
- SELECT Vendor_ID__c, Month__c, Quality_Score__c, Timeliness_Score__c,
276
  Safety_Score__c, Communication_Score__c, Final_Score__c, Certification_URL__c,
277
  Alert_Flag__c
278
  FROM Subcontractor_Performance_Score__c
279
  WHERE Month__c = '2025-05-01'
280
  """
281
- result = sf.query(query)
282
- vendor_logs.clear() # Clear existing logs and repopulate from Salesforce
 
 
 
 
 
 
283
  for record in result['records']:
 
 
 
 
 
 
 
 
284
  vendor_logs.append({
285
- 'vendorId': record['Vendor_ID__c'],
286
- 'vendorLogName': f"Vendor {record['Vendor_ID__c']}", # Placeholder; fetch actual name if needed
287
- 'scores': {
288
- 'qualityScore': record['Quality_Score__c'],
289
- 'timelinessScore': record['Timeliness_Score__c'],
290
- 'safetyScore': record['Safety_Score__c'],
291
- 'communicationScore': record['Communication_Score__c'],
292
- 'finalScore': record['Final_Score__c']
293
- },
294
  'extracted': True
295
  })
296
 
@@ -325,25 +360,44 @@ def get_dashboard():
325
  'status_text': status_text
326
  })
327
 
328
- # Render the template with the data
329
- return render_template('dashboard.html',
330
- total_vendors=total_vendors,
331
- performance_alerts=performance_alerts,
332
- percent_alerts=round(performance_alerts/total_vendors*100, 1) if total_vendors else 0,
333
- top_performers=top_performers,
334
- percent_top=round(top_performers/total_vendors*100, 1) if total_vendors else 0,
335
- improving_vendors=improving_vendors,
336
- percent_improving=round(improving_vendors/total_vendors*100, 1) if total_vendors else 0,
337
- top_logs=top_logs,
338
- alert_logs=alert_logs,
339
- top_performing_logs=top_performing_logs,
340
- vendor_logs=vendor_logs,
341
- sorted_logs=sorted_logs
342
- )
 
 
 
343
  except Exception as e:
344
  error_trace = traceback.format_exc()
345
  logger.error(f"Error in / endpoint: {str(e)}\nStack trace:\n{error_trace}")
346
- return jsonify({'error': f"Error generating dashboard: {str(e)}"}), 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
 
348
  @app.route('/document', methods=['GET'])
349
  def get_document():
 
10
  from datetime import datetime
11
  from simple_salesforce import Salesforce
12
 
13
+ # Set up logging with more detail
14
+ logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
15
  logger = logging.getLogger(__name__)
16
 
17
  app = Flask(__name__)
 
35
  domain=SF_DOMAIN
36
  )
37
  logger.info("Successfully connected to Salesforce")
38
+
39
+ # Debug: Describe the Subcontractor_Performance_Score__c object to log its fields
40
+ object_description = sf.Subcontractor_Performance_Score__c.describe()
41
+ logger.info("Fields on Subcontractor_Performance_Score__c:")
42
+ for field in object_description['fields']:
43
+ logger.info(f"Field Name: {field['name']}")
44
  except Exception as e:
45
  logger.error(f"Failed to connect to Salesforce: {str(e)}")
46
  raise ValueError("Failed to connect to Salesforce")
 
64
  def fetch_vendor_logs_from_salesforce():
65
  """Fetch vendor logs from Salesforce to send to Hugging Face."""
66
  try:
67
+ # Validate Salesforce session
68
+ if not sf.session_id:
69
+ logger.error("Salesforce session is invalid")
70
+ raise ValueError("Salesforce session is invalid")
71
+
72
+ # Use a more flexible query
73
  query = """
74
+ SELECT Id, Vendor_Log_Id__c, VendorId__c, Work_Details__c, Quality_Report__c,
75
  Incident_Log__c, Work_Completion_Date__c, Actual_Completion_Date__c,
76
  Vendor_Log_Name__c, Delay_Days__c, Project__c
77
  FROM Vendor_Log__c
78
+ WHERE CreatedDate >= 2025-05-01T00:00:00Z AND CreatedDate <= 2025-05-31T23:59:59Z
79
  """
80
  result = sf.query(query)
81
  logs = []
82
  for record in result['records']:
83
+ # Handle missing fields with defaults
84
  log = VendorLog(
85
+ vendorLogId=record.get('Vendor_Log_Id__c', 'Unknown'),
86
+ vendorId=record.get('VendorId__c', 'Unknown'),
87
+ workDetails=record.get('Work_Details__c', '0% completed'),
88
+ qualityReport=record.get('Quality_Report__c', '0% quality'),
89
+ incidentLog=record.get('Incident_Log__c', 'None'),
90
+ workCompletionDate=record.get('Work_Completion_Date__c', '2025-05-01'),
91
+ actualCompletionDate=record.get('Actual_Completion_Date__c', '2025-05-01'),
92
+ vendorLogName=record.get('Vendor_Log_Name__c', 'Unknown Vendor'),
93
+ delayDays=record.get('Delay_Days__c', 0),
94
+ project=record.get('Project__c', 'Unknown Project')
95
  )
96
  logs.append(log)
97
+ logger.info(f"Fetched {len(logs)} vendor logs from Salesforce")
98
  return logs
99
  except Exception as e:
100
  logger.error(f"Error fetching vendor logs from Salesforce: {str(e)}")
101
+ return []
102
 
103
  def calculate_scores_with_hugging_face(log: VendorLog):
104
  """Send data to Hugging Face and get scores (mocked for now)."""
 
114
  # Mocked Hugging Face API call (replace with actual API call)
115
  # headers = {"Authorization": f"Bearer {HUGGING_FACE_API_TOKEN}"}
116
  # response = requests.post(HUGGING_FACE_API_URL, json=payload, headers=headers)
117
+ # if response.status_code != 200:
118
+ # logger.error(f"Hugging Face API error: {response.text}")
119
+ # raise ValueError("Failed to get scores from Hugging Face")
120
  # scores = response.json()
121
 
122
  # Mocked response for now
 
124
  'qualityScore': float(log.qualityReport.replace('% quality', '')),
125
  'timelinessScore': 100.0 if log.delayDays <= 0 else 80.0 if log.delayDays <= 3 else 60.0 if log.delayDays <= 7 else 40.0,
126
  'safetyScore': {'None': 100.0, 'Low': 80.0, 'Minor': 80.0, 'Medium': 50.0, 'High': 20.0}.get(log.incidentLog, 100.0),
127
+ 'communicationScore': 0.0,
128
+ 'finalScore': 0.0
129
  }
130
  scores['communicationScore'] = (scores['qualityScore'] * 0.33 + scores['timelinessScore'] * 0.33 + scores['safetyScore'] * 0.33)
131
  scores['finalScore'] = (scores['qualityScore'] + scores['timelinessScore'] + scores['safetyScore'] + scores['communicationScore']) / 4
 
134
  for key in scores:
135
  scores[key] = round(scores[key], 2)
136
 
137
+ logger.debug(f"Calculated scores for vendor {log.vendorId}: {scores}")
138
  return scores
139
  except Exception as e:
140
  logger.error(f"Error calculating scores with Hugging Face: {str(e)}")
 
166
  return "Poor: Communication issues detected"
167
  except Exception as e:
168
  logger.error(f"Error generating feedback: {str(e)}")
169
+ return "Feedback unavailable"
170
 
171
  def generate_pdf(vendor_id: str, vendor_log_name: str, scores: dict):
172
  try:
173
+ filename = f'report_{vendor_id}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.pdf'
174
  c = canvas.Canvas(filename, pagesize=letter)
175
  c.setFont('Helvetica', 12)
176
  c.drawString(100, 750, 'Subcontractor Performance Report')
 
185
 
186
  with open(filename, 'rb') as f:
187
  pdf_content = f.read()
188
+
189
+ # Clean up the file
190
+ try:
191
+ os.remove(filename)
192
+ except Exception as e:
193
+ logger.warning(f"Could not delete temporary PDF file {filename}: {str(e)}")
194
+
195
  return pdf_content
196
  except Exception as e:
197
  logger.error(f"Error generating PDF: {str(e)}")
 
207
  return final_score == lowest_score
208
  except Exception as e:
209
  logger.error(f"Error determining alert flag: {str(e)}")
210
+ return False
211
 
212
  @app.route('/score', methods=['POST'])
213
  def score_vendor():
 
215
  # Validate the Authorization header
216
  authorization = request.headers.get('Authorization')
217
  if not authorization:
218
+ logger.warning("Authorization header missing in request")
219
  return jsonify({'error': 'Authorization header missing'}), 401
220
 
221
  # Parse the request data
222
  data = request.get_json()
223
  if not data:
224
+ logger.warning("Invalid or missing JSON data in request")
225
  return jsonify({'error': 'Invalid request data'}), 400
226
 
227
  # Validate and create VendorLog instance
 
230
 
231
  # Validate Salesforce session
232
  if not sf.session_id:
233
+ logger.error("Salesforce session invalid")
234
  return jsonify({'error': 'Salesforce session invalid'}), 401
235
 
236
  # Calculate scores using Hugging Face
 
259
  'extracted': True
260
  })
261
 
262
+ # Save scores and PDF to Salesforce
263
  try:
264
  sf.Subcontractor_Performance_Score__c.create({
265
+ 'VendorId__c': log.vendorId, # Updated field name
266
  'Month__c': datetime.now().strftime('%Y-%m-%d'),
267
  'Quality_Score__c': scores['qualityScore'],
268
  'Timeliness_Score__c': scores['timelinessScore'],
269
  'Safety_Score__c': scores['safetyScore'],
270
  'Communication_Score__c': scores['communicationScore'],
271
+ 'Final_Score__c': scores['finalScore'],
272
+ 'Certification_URL__c': pdf_base64,
273
  'Alert_Flag__c': alert_flag
274
  })
275
  logger.info(f"Successfully saved scores to Salesforce for Vendor Log: {log.vendorLogId}")
 
297
  @app.route('/', methods=['GET'])
298
  def get_dashboard():
299
  try:
300
+ # Fetch data from Salesforce with updated field name
301
  query = """
302
+ SELECT VendorId__c, Month__c, Quality_Score__c, Timeliness_Score__c,
303
  Safety_Score__c, Communication_Score__c, Final_Score__c, Certification_URL__c,
304
  Alert_Flag__c
305
  FROM Subcontractor_Performance_Score__c
306
  WHERE Month__c = '2025-05-01'
307
  """
308
+ try:
309
+ result = sf.query(query)
310
+ except Exception as e:
311
+ logger.error(f"Error querying Salesforce: {str(e)}")
312
+ # Fallback to empty data to render the dashboard
313
+ result = {'records': []}
314
+
315
+ vendor_logs.clear()
316
  for record in result['records']:
317
+ # Handle missing or null scores
318
+ scores = {
319
+ 'qualityScore': record.get('Quality_Score__c', 0.0) or 0.0,
320
+ 'timelinessScore': record.get('Timeliness_Score__c', 0.0) or 0.0,
321
+ 'safetyScore': record.get('Safety_Score__c', 0.0) or 0.0,
322
+ 'communicationScore': record.get('Communication_Score__c', 0.0) or 0.0,
323
+ 'finalScore': record.get('Final_Score__c', 0.0) or 0.0
324
+ }
325
  vendor_logs.append({
326
+ 'vendorId': record.get('VendorId__c', 'Unknown'),
327
+ 'vendorLogName': f"Vendor {record.get('VendorId__c', 'Unknown')}",
328
+ 'scores': scores,
 
 
 
 
 
 
329
  'extracted': True
330
  })
331
 
 
360
  'status_text': status_text
361
  })
362
 
363
+ # Ensure all variables are defined for the template
364
+ template_data = {
365
+ 'total_vendors': total_vendors,
366
+ 'performance_alerts': performance_alerts,
367
+ 'percent_alerts': round(performance_alerts/total_vendors*100, 1) if total_vendors else 0,
368
+ 'top_performers': top_performers,
369
+ 'percent_top': round(top_performers/total_vendors*100, 1) if total_vendors else 0,
370
+ 'improving_vendors': improving_vendors,
371
+ 'percent_improving': round(improving_vendors/total_vendors*100, 1) if total_vendors else 0,
372
+ 'top_logs': top_logs,
373
+ 'alert_logs': alert_logs,
374
+ 'top_performing_logs': top_performing_logs,
375
+ 'vendor_logs': vendor_logs,
376
+ 'sorted_logs': sorted_logs
377
+ }
378
+
379
+ logger.info(f"Rendering dashboard with data: {template_data}")
380
+ return render_template('dashboard.html', **template_data)
381
  except Exception as e:
382
  error_trace = traceback.format_exc()
383
  logger.error(f"Error in / endpoint: {str(e)}\nStack trace:\n{error_trace}")
384
+ # Fallback to render the dashboard with empty data
385
+ template_data = {
386
+ 'total_vendors': 0,
387
+ 'performance_alerts': 0,
388
+ 'percent_alerts': 0,
389
+ 'top_performers': 0,
390
+ 'percent_top': 0,
391
+ 'improving_vendors': 0,
392
+ 'percent_improving': 0,
393
+ 'top_logs': [],
394
+ 'alert_logs': [],
395
+ 'top_performing_logs': [],
396
+ 'vendor_logs': [],
397
+ 'sorted_logs': []
398
+ }
399
+ logger.info("Rendering dashboard with fallback data due to error")
400
+ return render_template('dashboard.html', **template_data)
401
 
402
  @app.route('/document', methods=['GET'])
403
  def get_document():