Dineshpopuri commited on
Commit
3ce8a35
·
verified ·
1 Parent(s): 4b128ec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -25
app.py CHANGED
@@ -8,6 +8,7 @@ import os
8
  from huggingface_hub import InferenceClient
9
  from retry import retry
10
  import time
 
11
 
12
  # Print statement to confirm script initialization
13
  print("Starting Project Closure Readiness Evaluator app...")
@@ -94,7 +95,10 @@ def summarize_text(text, max_length=100, min_length=30):
94
  return text # Fallback to original text
95
 
96
  # Create Salesforce record in custom object Project_Closure_Handover__c
97
- def create_salesforce_record(score, checklist_summary, missing_summary, status):
 
 
 
98
  if not SALESFORCE_AVAILABLE:
99
  logging.error("Salesforce library not available. Skipping record creation.")
100
  return "Salesforce library not available"
@@ -109,22 +113,51 @@ def create_salesforce_record(score, checklist_summary, missing_summary, status):
109
  summarized_checklist = summarize_text(checklist_summary)
110
  summarized_missing = summarize_text(missing_summary)
111
 
112
- # Ensure inputs are strings and sanitized
113
  score = float(score) if score is not None else 0.0
114
  checklist_summary = str(checklist_summary) if checklist_summary else ""
115
  summarized_checklist = str(summarized_checklist) if summarized_checklist else ""
116
  missing_summary = str(missing_summary) if missing_summary else ""
117
  summarized_missing = str(summarized_missing) if summarized_missing else ""
118
  status = str(status) if status else ""
 
 
 
 
 
 
 
 
 
 
 
119
 
120
  # Create a record in the custom object Project_Closure_Handover__c
121
  record = {
122
  "Readiness_Score__c": score,
123
  "Checklist_Summary__c": checklist_summary,
124
- "Missing_Documents__c": missing_summary,
125
  "Status__c": status,
126
- "Summarized_Missing_Items__c": summarized_missing
 
 
 
 
 
 
 
 
 
 
 
127
  }
 
 
 
 
 
 
 
128
  logging.debug(f"Attempting to create Salesforce record: {record}")
129
  result = sf.Project_Closure_Handover__c.create(record)
130
  logging.info(f"Successfully created Salesforce record: {result}")
@@ -143,10 +176,10 @@ def sanitize_input(text):
143
  return bleach.clean(text.strip())
144
 
145
  # Rule-based completeness engine with weighted scoring
146
- def evaluate_readiness(logs, qa_report, punch_list_text):
147
  try:
148
  # Log inputs for debugging
149
- logging.info(f"Inputs - Logs: {logs}, QA Report: {qa_report}, Punch List: {punch_list_text}")
150
 
151
  # Initialize score and lists for tracking
152
  score = 0
@@ -162,6 +195,10 @@ def evaluate_readiness(logs, qa_report, punch_list_text):
162
  logs = sanitize_input(logs)
163
  qa_report = sanitize_input(qa_report)
164
  punch_list_text = sanitize_input(punch_list_text)
 
 
 
 
165
 
166
  # Process Project Logs (30% weight)
167
  log_keywords = r"complete|handover done|finished|closed|successful"
@@ -196,6 +233,9 @@ def evaluate_readiness(logs, qa_report, punch_list_text):
196
  checklist_details.append("Punch List: Pending")
197
  logging.info(f"Punch List Check: {'Pass' if punch_pass else 'Fail'}, Final Score: {score}%")
198
 
 
 
 
199
  # Handle critical issues (escalation)
200
  escalated = any("incomplete" in item.lower() or "missing" in item.lower() for item in missing_items)
201
  status = "Escalated" if escalated else ("Completed" if not missing_items else "Pending")
@@ -215,17 +255,14 @@ def evaluate_readiness(logs, qa_report, punch_list_text):
215
  </div>
216
  """
217
 
218
- # Automatically create Salesforce record
219
- sf_result = create_salesforce_record(score, checklist_summary, missing_summary, status)
220
- logging.info(f"Salesforce record creation result: {sf_result}")
221
-
222
- return score, checklist_summary, missing_summary, status, progress_bar
223
  except Exception as e:
224
  logging.error(f"Error in evaluate_readiness: {str(e)}")
225
  raise
226
 
227
  # Generate PDF report with signature slots and write to a temporary file
228
- def generate_pdf(score, checklist_summary, missing_summary, status):
229
  try:
230
  # Sanitize inputs to ensure they are strings and handle None
231
  logging.info("Sanitizing inputs for PDF generation")
@@ -233,11 +270,25 @@ def generate_pdf(score, checklist_summary, missing_summary, status):
233
  checklist_summary = str(checklist_summary) if checklist_summary is not None else ""
234
  missing_summary = str(missing_summary) if missing_summary is not None else ""
235
  status = str(status) if status is not None else ""
 
 
 
 
 
 
 
236
 
237
  # Remove non-ASCII characters to prevent rendering issues
238
  checklist_summary = checklist_summary.encode('ascii', 'ignore').decode('ascii')
239
  missing_summary = missing_summary.encode('ascii', 'ignore').decode('ascii')
240
  status = status.encode('ascii', 'ignore').decode('ascii')
 
 
 
 
 
 
 
241
 
242
  # Define the temporary file path
243
  pdf_path = "temp_readiness_report.pdf"
@@ -254,13 +305,17 @@ def generate_pdf(score, checklist_summary, missing_summary, status):
254
  # Draw basic fields using Times-Roman
255
  logging.info("Drawing basic fields")
256
  c.setFont("Times-Roman", 12)
257
- c.drawString(50, 720, f"Readiness Score: {score}%")
258
- c.drawString(50, 700, f"Status: {status}")
259
- c.drawString(50, 680, "Checklist Summary:")
 
 
 
 
260
 
261
  # Draw checklist summary with Y-position overflow handling
262
  logging.info("Drawing checklist summary")
263
- y = 660
264
  BOTTOM_MARGIN = 50 # Minimum Y position before creating a new page
265
  for line in checklist_summary.split("\n"):
266
  if y < BOTTOM_MARGIN:
@@ -279,7 +334,7 @@ def generate_pdf(score, checklist_summary, missing_summary, status):
279
  c.setFont("Times-Roman", 12)
280
  y = 750
281
  c.drawString(50, y - 20, "Missing Items:")
282
-
283
  if y - 40 < BOTTOM_MARGIN:
284
  logging.info("Y position below margin, creating new page")
285
  c.showPage()
@@ -287,19 +342,61 @@ def generate_pdf(score, checklist_summary, missing_summary, status):
287
  y = 750
288
  c.drawString(50, y - 40, missing_summary)
289
 
 
 
 
 
 
 
 
290
  if y - 80 < BOTTOM_MARGIN:
291
  logging.info("Y position below margin, creating new page")
292
  c.showPage()
293
  c.setFont("Times-Roman", 12)
294
  y = 750
295
- c.drawString(50, y - 80, "Stakeholder Signature: ____________________")
296
 
297
  if y - 100 < BOTTOM_MARGIN:
298
  logging.info("Y position below margin, creating new page")
299
  c.showPage()
300
  c.setFont("Times-Roman", 12)
301
  y = 750
302
- c.drawString(50, y - 100, "Date: ____________________")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
 
304
  # Finalize the PDF
305
  logging.info("Finalizing PDF")
@@ -311,7 +408,7 @@ def generate_pdf(score, checklist_summary, missing_summary, status):
311
  raise FileNotFoundError(f"PDF file {pdf_path} was not created")
312
 
313
  logging.info(f"PDF generated successfully at {pdf_path}")
314
- return pdf_path, "PDF generation triggered successfully" # Return the file path and debug message
315
  except Exception as e:
316
  logging.error(f"Error in generate_pdf: {str(e)}")
317
  raise
@@ -336,6 +433,10 @@ with gr.Blocks(css="""
336
  logs_input = gr.Textbox(label="Project Logs", lines=5, placeholder="Enter project logs (e.g., 'Project complete, handover done')")
337
  qa_input = gr.Textbox(label="QA Report", placeholder="Enter QA status (e.g., 'Approved')")
338
  punch_input = gr.Textbox(label="Punch List (Plain Text)", placeholder="Enter punch list status (e.g., 'None' or 'Resolved')")
 
 
 
 
339
  submit_btn = gr.Button("Evaluate Readiness")
340
  with gr.Column(scale=3):
341
  score_output = gr.Number(label="Readiness Score (%)")
@@ -353,18 +454,23 @@ with gr.Blocks(css="""
353
  # Connect inputs to evaluate_readiness
354
  submit_btn.click(
355
  fn=evaluate_readiness,
356
- inputs=[logs_input, qa_input, punch_input],
357
- outputs=[score_output, checklist_output, missing_output, status_output, progress_output]
 
358
  )
359
 
360
- # Connect PDF button to generate_pdf
361
  pdf_btn.click(
362
  fn=generate_pdf,
363
- inputs=[score_output, checklist_output, missing_output, status_output],
364
  outputs=[pdf_output, pdf_debug]
 
 
 
 
365
  )
366
  demo.launch()
367
 
368
  # Comment out demo.launch() for Hugging Face Spaces deployment
369
  # if __name__ == "__main__":
370
-
 
8
  from huggingface_hub import InferenceClient
9
  from retry import retry
10
  import time
11
+ from datetime import datetime
12
 
13
  # Print statement to confirm script initialization
14
  print("Starting Project Closure Readiness Evaluator app...")
 
95
  return text # Fallback to original text
96
 
97
  # Create Salesforce record in custom object Project_Closure_Handover__c
98
+ def create_salesforce_record(
99
+ score, checklist_summary, missing_summary, status, escalated, logs, qa_report, punch_list_text,
100
+ open_punch_items, project_id, start_date, end_date, owner_id, pdf_path=None
101
+ ):
102
  if not SALESFORCE_AVAILABLE:
103
  logging.error("Salesforce library not available. Skipping record creation.")
104
  return "Salesforce library not available"
 
113
  summarized_checklist = summarize_text(checklist_summary)
114
  summarized_missing = summarize_text(missing_summary)
115
 
116
+ # Ensure inputs are properly formatted
117
  score = float(score) if score is not None else 0.0
118
  checklist_summary = str(checklist_summary) if checklist_summary else ""
119
  summarized_checklist = str(summarized_checklist) if summarized_checklist else ""
120
  missing_summary = str(missing_summary) if missing_summary else ""
121
  summarized_missing = str(summarized_missing) if summarized_missing else ""
122
  status = str(status) if status else ""
123
+ logs = str(logs) if logs else ""
124
+ qa_report = str(qa_report) if qa_report else ""
125
+ punch_list_text = str(punch_list_text) if punch_list_text else ""
126
+ missing_documents = len(missing_summary.split(", ")) if missing_summary and missing_summary != "None" else 0
127
+ open_punch_items = int(open_punch_items) if open_punch_items is not None else 0
128
+ project_id = str(project_id) if project_id else None
129
+ owner_id = str(owner_id) if owner_id else None
130
+ start_date = str(start_date) if start_date else None
131
+ end_date = str(end_date) if end_date else None
132
+ evaluated_at = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ") # Salesforce Date/Time format
133
+ alert_sent = escalated # Set Alert_Sent__c based on escalation flag
134
 
135
  # Create a record in the custom object Project_Closure_Handover__c
136
  record = {
137
  "Readiness_Score__c": score,
138
  "Checklist_Summary__c": checklist_summary,
139
+ "Missing_Documents__c": missing_documents,
140
  "Status__c": status,
141
+ "Summarized_Missing_Items__c": summarized_missing,
142
+ "Alert_Sent__c": alert_sent,
143
+ "Client_PDF_Pack_URL__c": pdf_path if pdf_path else "",
144
+ "Closure_Pack_URL__c": "", # Placeholder; update if you have a closure pack URL
145
+ "End_Date__c": end_date,
146
+ "Escalation_Flag__c": escalated,
147
+ "Evaluated_At__c": evaluated_at,
148
+ "Logs__c": logs,
149
+ "Open_Punch_Items__c": open_punch_items,
150
+ "Punch_List__c": punch_list_text,
151
+ "QA_Report__c": qa_report,
152
+ "Start_Date__c": start_date
153
  }
154
+
155
+ # Add optional fields if provided
156
+ if project_id:
157
+ record["Project_ID__c"] = project_id
158
+ if owner_id:
159
+ record["OwnerId"] = owner_id
160
+
161
  logging.debug(f"Attempting to create Salesforce record: {record}")
162
  result = sf.Project_Closure_Handover__c.create(record)
163
  logging.info(f"Successfully created Salesforce record: {result}")
 
176
  return bleach.clean(text.strip())
177
 
178
  # Rule-based completeness engine with weighted scoring
179
+ def evaluate_readiness(logs, qa_report, punch_list_text, project_id, start_date, end_date, owner_id):
180
  try:
181
  # Log inputs for debugging
182
+ logging.info(f"Inputs - Logs: {logs}, QA Report: {qa_report}, Punch List: {punch_list_text}, Project ID: {project_id}, Start Date: {start_date}, End Date: {end_date}, Owner ID: {owner_id}")
183
 
184
  # Initialize score and lists for tracking
185
  score = 0
 
195
  logs = sanitize_input(logs)
196
  qa_report = sanitize_input(qa_report)
197
  punch_list_text = sanitize_input(punch_list_text)
198
+ project_id = sanitize_input(project_id)
199
+ start_date = sanitize_input(start_date)
200
+ end_date = sanitize_input(end_date)
201
+ owner_id = sanitize_input(owner_id)
202
 
203
  # Process Project Logs (30% weight)
204
  log_keywords = r"complete|handover done|finished|closed|successful"
 
233
  checklist_details.append("Punch List: Pending")
234
  logging.info(f"Punch List Check: {'Pass' if punch_pass else 'Fail'}, Final Score: {score}%")
235
 
236
+ # Calculate open punch items
237
+ open_punch_items = 0 if punch_pass else len(punch_list_text.split(",")) if punch_list_text else 1
238
+
239
  # Handle critical issues (escalation)
240
  escalated = any("incomplete" in item.lower() or "missing" in item.lower() for item in missing_items)
241
  status = "Escalated" if escalated else ("Completed" if not missing_items else "Pending")
 
255
  </div>
256
  """
257
 
258
+ # Store inputs for PDF generation and Salesforce record
259
+ return (score, checklist_summary, missing_summary, status, progress_bar, escalated, logs, qa_report, punch_list_text, open_punch_items, project_id, start_date, end_date, owner_id)
 
 
 
260
  except Exception as e:
261
  logging.error(f"Error in evaluate_readiness: {str(e)}")
262
  raise
263
 
264
  # Generate PDF report with signature slots and write to a temporary file
265
+ def generate_pdf(score, checklist_summary, missing_summary, status, logs, qa_report, punch_list_text, project_id, start_date, end_date, owner_id):
266
  try:
267
  # Sanitize inputs to ensure they are strings and handle None
268
  logging.info("Sanitizing inputs for PDF generation")
 
270
  checklist_summary = str(checklist_summary) if checklist_summary is not None else ""
271
  missing_summary = str(missing_summary) if missing_summary is not None else ""
272
  status = str(status) if status is not None else ""
273
+ logs = str(logs) if logs else ""
274
+ qa_report = str(qa_report) if qa_report else ""
275
+ punch_list_text = str(punch_list_text) if punch_list_text else ""
276
+ project_id = str(project_id) if project_id else "Not Provided"
277
+ start_date = str(start_date) if start_date else "Not Provided"
278
+ end_date = str(end_date) if end_date else "Not Provided"
279
+ owner_id = str(owner_id) if owner_id else "Not Provided"
280
 
281
  # Remove non-ASCII characters to prevent rendering issues
282
  checklist_summary = checklist_summary.encode('ascii', 'ignore').decode('ascii')
283
  missing_summary = missing_summary.encode('ascii', 'ignore').decode('ascii')
284
  status = status.encode('ascii', 'ignore').decode('ascii')
285
+ logs = logs.encode('ascii', 'ignore').decode('ascii')
286
+ qa_report = qa_report.encode('ascii', 'ignore').decode('ascii')
287
+ punch_list_text = punch_list_text.encode('ascii', 'ignore').decode('ascii')
288
+ project_id = project_id.encode('ascii', 'ignore').decode('ascii')
289
+ start_date = start_date.encode('ascii', 'ignore').decode('ascii')
290
+ end_date = end_date.encode('ascii', 'ignore').decode('ascii')
291
+ owner_id = owner_id.encode('ascii', 'ignore').decode('ascii')
292
 
293
  # Define the temporary file path
294
  pdf_path = "temp_readiness_report.pdf"
 
305
  # Draw basic fields using Times-Roman
306
  logging.info("Drawing basic fields")
307
  c.setFont("Times-Roman", 12)
308
+ c.drawString(50, 720, f"Project ID: {project_id}")
309
+ c.drawString(50, 700, f"Readiness Score: {score}%")
310
+ c.drawString(50, 680, f"Status: {status}")
311
+ c.drawString(50, 660, f"Start Date: {start_date}")
312
+ c.drawString(50, 640, f"End Date: {end_date}")
313
+ c.drawString(50, 620, f"Owner ID: {owner_id}")
314
+ c.drawString(50, 600, "Checklist Summary:")
315
 
316
  # Draw checklist summary with Y-position overflow handling
317
  logging.info("Drawing checklist summary")
318
+ y = 580
319
  BOTTOM_MARGIN = 50 # Minimum Y position before creating a new page
320
  for line in checklist_summary.split("\n"):
321
  if y < BOTTOM_MARGIN:
 
334
  c.setFont("Times-Roman", 12)
335
  y = 750
336
  c.drawString(50, y - 20, "Missing Items:")
337
+
338
  if y - 40 < BOTTOM_MARGIN:
339
  logging.info("Y position below margin, creating new page")
340
  c.showPage()
 
342
  y = 750
343
  c.drawString(50, y - 40, missing_summary)
344
 
345
+ if y - 60 < BOTTOM_MARGIN:
346
+ logging.info("Y position below margin, creating new page")
347
+ c.showPage()
348
+ c.setFont("Times-Roman", 12)
349
+ y = 750
350
+ c.drawString(50, y - 60, "Logs:")
351
+
352
  if y - 80 < BOTTOM_MARGIN:
353
  logging.info("Y position below margin, creating new page")
354
  c.showPage()
355
  c.setFont("Times-Roman", 12)
356
  y = 750
357
+ c.drawString(50, y - 80, logs[:100] + "..." if len(logs) > 100 else logs)
358
 
359
  if y - 100 < BOTTOM_MARGIN:
360
  logging.info("Y position below margin, creating new page")
361
  c.showPage()
362
  c.setFont("Times-Roman", 12)
363
  y = 750
364
+ c.drawString(50, y - 100, "QA Report:")
365
+
366
+ if y - 120 < BOTTOM_MARGIN:
367
+ logging.info("Y position below margin, creating new page")
368
+ c.showPage()
369
+ c.setFont("Times-Roman", 12)
370
+ y = 750
371
+ c.drawString(50, y - 120, qa_report[:100] + "..." if len(qa_report) > 100 else qa_report)
372
+
373
+ if y - 140 < BOTTOM_MARGIN:
374
+ logging.info("Y position below margin, creating new page")
375
+ c.showPage()
376
+ c.setFont("Times-Roman", 12)
377
+ y = 750
378
+ c.drawString(50, y - 140, "Punch List:")
379
+
380
+ if y - 160 < BOTTOM_MARGIN:
381
+ logging.info("Y position below margin, creating new page")
382
+ c.showPage()
383
+ c.setFont("Times-Roman", 12)
384
+ y = 750
385
+ c.drawString(50, y - 160, punch_list_text[:100] + "..." if len(punch_list_text) > 100 else punch_list_text)
386
+
387
+ if y - 180 < BOTTOM_MARGIN:
388
+ logging.info("Y position below margin, creating new page")
389
+ c.showPage()
390
+ c.setFont("Times-Roman", 12)
391
+ y = 750
392
+ c.drawString(50, y - 180, "Stakeholder Signature: ____________________")
393
+
394
+ if y - 200 < BOTTOM_MARGIN:
395
+ logging.info("Y position below margin, creating new page")
396
+ c.showPage()
397
+ c.setFont("Times-Roman", 12)
398
+ y = 750
399
+ c.drawString(50, y - 200, "Date: ____________________")
400
 
401
  # Finalize the PDF
402
  logging.info("Finalizing PDF")
 
408
  raise FileNotFoundError(f"PDF file {pdf_path} was not created")
409
 
410
  logging.info(f"PDF generated successfully at {pdf_path}")
411
+ return pdf_path, "PDF generation triggered successfully"
412
  except Exception as e:
413
  logging.error(f"Error in generate_pdf: {str(e)}")
414
  raise
 
433
  logs_input = gr.Textbox(label="Project Logs", lines=5, placeholder="Enter project logs (e.g., 'Project complete, handover done')")
434
  qa_input = gr.Textbox(label="QA Report", placeholder="Enter QA status (e.g., 'Approved')")
435
  punch_input = gr.Textbox(label="Punch List (Plain Text)", placeholder="Enter punch list status (e.g., 'None' or 'Resolved')")
436
+ project_id_input = gr.Textbox(label="Project ID", placeholder="Enter Salesforce Project ID (e.g., 'a0Axx000000xxxx')")
437
+ start_date_input = gr.Textbox(label="Start Date (YYYY-MM-DD)", placeholder="e.g., 2025-05-01")
438
+ end_date_input = gr.Textbox(label="End Date (YYYY-MM-DD)", placeholder="e.g., 2025-05-19")
439
+ owner_id_input = gr.Textbox(label="Owner ID", placeholder="Enter Salesforce User/Group ID (e.g., '005xx000000xxxx')")
440
  submit_btn = gr.Button("Evaluate Readiness")
441
  with gr.Column(scale=3):
442
  score_output = gr.Number(label="Readiness Score (%)")
 
454
  # Connect inputs to evaluate_readiness
455
  submit_btn.click(
456
  fn=evaluate_readiness,
457
+ inputs=[logs_input, qa_input, punch_input, project_id_input, start_date_input, end_date_input, owner_id_input],
458
+ outputs=[score_output, checklist_output, missing_output, status_output, progress_output,
459
+ gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State()]
460
  )
461
 
462
+ # Connect PDF button to generate_pdf and create Salesforce record
463
  pdf_btn.click(
464
  fn=generate_pdf,
465
+ inputs=[score_output, checklist_output, missing_output, status_output, gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State()],
466
  outputs=[pdf_output, pdf_debug]
467
+ ).then(
468
+ fn=create_salesforce_record,
469
+ inputs=[score_output, checklist_output, missing_output, status_output, gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), gr.State(), pdf_output],
470
+ outputs=gr.Textbox(label="Salesforce Record Creation Status")
471
  )
472
  demo.launch()
473
 
474
  # Comment out demo.launch() for Hugging Face Spaces deployment
475
  # if __name__ == "__main__":
476
+ # demo.launch()