MaheshP98 commited on
Commit
f58d4f9
·
verified ·
1 Parent(s): 26d46da

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -20
app.py CHANGED
@@ -10,6 +10,7 @@ from datetime import datetime
10
  from reportlab.lib.pagesizes import letter
11
  from reportlab.pdfgen import canvas
12
  from reportlab.lib.utils import ImageReader
 
13
 
14
  # Set up logging
15
  logging.basicConfig(level=logging.DEBUG)
@@ -50,7 +51,7 @@ def process_uploaded_file(file):
50
  return planned_cost, actual_spend, line_items
51
 
52
  # Function to generate a bar chart for the PDF report and Gradio UI with amount labels
53
- def generate_plot(planned_cost_inr, actual_spend_inr, forecast_cost_inr):
54
  fig, ax = plt.subplots(figsize=(8, 6))
55
  categories = ['Planned Cost', 'Actual Spend', 'Forecasted Cost']
56
  values = [planned_cost_inr, actual_spend_inr, forecast_cost_inr]
@@ -82,8 +83,47 @@ def generate_plot(planned_cost_inr, actual_spend_inr, forecast_cost_inr):
82
  plt.close()
83
  return gradio_image, buf_pdf
84
 
85
- # Function to generate a PDF report locally
86
- def generate_pdf(planned_cost_inr, actual_spend_inr, forecast_cost_inr, total_risk, risk_percentage, insights, status, top_causes, category, project_phase, material_cost_index, labor_index, scope_change_impact, alert_message, chart_image):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  pdf_path = f"budget_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
88
  c = canvas.Canvas(pdf_path, pagesize=letter)
89
  width, height = letter
@@ -95,6 +135,11 @@ def generate_pdf(planned_cost_inr, actual_spend_inr, forecast_cost_inr, total_ri
95
  # Prediction Metrics with Indian formatting
96
  c.setFont("Helvetica", 12)
97
  y_position = height - 100
 
 
 
 
 
98
  c.drawString(50, y_position, f"Category: {category}")
99
  y_position -= 20
100
  c.drawString(50, y_position, f"Project Phase: {project_phase}")
@@ -124,8 +169,8 @@ def generate_pdf(planned_cost_inr, actual_spend_inr, forecast_cost_inr, total_ri
124
  c.drawString(50, y_position, f"Alert: {alert_message}")
125
  y_position -= 40
126
 
127
- # Add the chart
128
- chart_reader = ImageReader(chart_image)
129
  c.drawImage(chart_reader, 50, y_position - 300, width=500, height=300)
130
 
131
  c.showPage()
@@ -175,7 +220,7 @@ def predict_risk(file, category, material_cost_index, labor_index, scope_change_
175
  try:
176
  planned_cost_inr, actual_spend_inr, line_items = process_uploaded_file(file)
177
  except Exception as e:
178
- return f"Error processing file: {str(e)}", None, None, None
179
 
180
  # Validate numeric inputs
181
  try:
@@ -184,7 +229,7 @@ def predict_risk(file, category, material_cost_index, labor_index, scope_change_
184
  scope_change_impact = float(scope_change_impact) if scope_change_impact else 0
185
  except ValueError:
186
  logger.error("Invalid input: Inputs must be numeric.")
187
- return "Error: All numeric inputs (material cost index, labor index, scope change impact) must be valid numbers.", None, None, None
188
 
189
  logger.debug(f"Starting prediction with inputs: planned_cost_inr={planned_cost_inr}, actual_spend_inr={actual_spend_inr}, "
190
  f"category={category}, material_cost_index={material_cost_index}, labor_index={labor_index}, "
@@ -229,15 +274,19 @@ def predict_risk(file, category, material_cost_index, labor_index, scope_change_
229
  # Check for >10% deviation and generate alert
230
  deviation = ((forecast_cost_inr - planned_cost_inr) / planned_cost_inr * 100) if planned_cost_inr > 0 else 0
231
  alert_message = "Alert: Forecasted cost exceeds planned cost by more than 10%. Notify finance and engineering teams." if deviation > 10 else "No alert triggered."
 
232
 
233
  logger.debug(f"Calculation results: total_risk={total_risk}, risk_percentage={risk_percentage}, forecast_cost_inr={forecast_cost_inr}, "
234
  f"insights={insights}, status={status}, top_causes={top_causes}, alert_message={alert_message}")
235
 
236
- # Generate the plot for Gradio and PDF
237
- chart_image, chart_image_pdf = generate_plot(planned_cost_inr, actual_spend_inr, forecast_cost_inr)
 
 
 
238
 
239
  # Generate local PDF report
240
- pdf_file = generate_pdf(planned_cost_inr, actual_spend_inr, forecast_cost_inr, total_risk, risk_percentage, insights, status, top_causes, category, project_phase, material_cost_index, labor_index, scope_change_impact, alert_message, chart_image_pdf)
241
 
242
  # Generate Excel file
243
  excel_file = generate_excel(planned_cost_inr, actual_spend_inr, forecast_cost_inr, total_risk, risk_percentage, insights, status, top_causes, category, project_phase, material_cost_index, labor_index, scope_change_impact, alert_message)
@@ -250,8 +299,7 @@ def predict_risk(file, category, material_cost_index, labor_index, scope_change_
250
  f"Risk Level: {risk_level}\n"
251
  f"Risk Percentage: {risk_percentage}%\n"
252
  f"Status: {status}\n"
253
- f"Insights: {insights} due to {top_causes.lower()}.\n"
254
- f"Alert: {alert_message}\n\n"
255
  f"Project Details\n"
256
  f"----------------------------------------\n"
257
  f"Category: {category}\n"
@@ -261,7 +309,7 @@ def predict_risk(file, category, material_cost_index, labor_index, scope_change_
261
  f"Scope Change Impact: {scope_change_impact}%\n\n"
262
  f"Forecast Chart\n"
263
  f"----------------------------------------\n"
264
- f"[Chart displayed below]\n\n"
265
  f"Detailed Metrics\n"
266
  f"----------------------------------------\n"
267
  f"Total Risk: {total_risk}\n"
@@ -272,7 +320,11 @@ def predict_risk(file, category, material_cost_index, labor_index, scope_change_
272
  f"Local PDF Report: [Download link below]\n"
273
  f"Excel Report: [Download link below]"
274
  )
275
- return output_text, chart_image, pdf_file, excel_file
 
 
 
 
276
 
277
  # Function to update Material Cost Index explanation based on category
278
  def update_material_cost_explanation(category):
@@ -309,7 +361,7 @@ def update_labor_explanation(category):
309
  f"A value above 150 flags a potential risk. Example: If the index is 160, labor costs are 60% higher than the baseline."
310
  )
311
 
312
- # Custom CSS for the golden button with adjusted size
313
  custom_css = """
314
  #submit-button {
315
  background-color: #FFD700 !important; /* Golden background */
@@ -331,7 +383,7 @@ custom_css = """
331
  # Custom Gradio Blocks interface
332
  with gr.Blocks(title="Budget Overrun Risk Estimator", css=custom_css) as demo:
333
  gr.Markdown("# Budget Overrun Risk Estimator")
334
- gr.Markdown("Upload a CSV file with budget line items (columns: 'Planned_Cost', 'Actual_Spend') or enter totals manually. All numeric fields are required.")
335
 
336
  with gr.Row():
337
  with gr.Column():
@@ -353,8 +405,21 @@ with gr.Blocks(title="Budget Overrun Risk Estimator", css=custom_css) as demo:
353
  submit_button = gr.Button("Submit", elem_id="submit-button")
354
 
355
  with gr.Column():
 
 
 
 
356
  output_text = gr.Textbox(label="Prediction Results", lines=20, max_lines=30)
357
- output_chart = gr.Image(label="Forecast Chart")
 
 
 
 
 
 
 
 
 
358
  output_pdf = gr.File(label="Download Local PDF Report")
359
  output_excel = gr.File(label="Download Excel Report")
360
 
@@ -372,10 +437,11 @@ with gr.Blocks(title="Budget Overrun Risk Estimator", css=custom_css) as demo:
372
 
373
  # Clear button functionality
374
  clear_button.click(
375
- fn=lambda: (None, "Plumbing", "", "", "", "Planning", "", None, None, None),
376
  outputs=[
377
  file_input, category_input, material_cost_input, labor_index_input,
378
- scope_change_input, project_phase_input, output_text, output_chart, output_pdf, output_excel
 
379
  ]
380
  )
381
 
@@ -383,7 +449,7 @@ with gr.Blocks(title="Budget Overrun Risk Estimator", css=custom_css) as demo:
383
  submit_button.click(
384
  fn=predict_risk,
385
  inputs=[file_input, category_input, material_cost_input, labor_index_input, scope_change_input, project_phase_input],
386
- outputs=[output_text, output_chart, output_pdf, output_excel]
387
  )
388
 
389
  # Launch the app
 
10
  from reportlab.lib.pagesizes import letter
11
  from reportlab.pdfgen import canvas
12
  from reportlab.lib.utils import ImageReader
13
+ from reportlab.lib.colors import red, black
14
 
15
  # Set up logging
16
  logging.basicConfig(level=logging.DEBUG)
 
51
  return planned_cost, actual_spend, line_items
52
 
53
  # Function to generate a bar chart for the PDF report and Gradio UI with amount labels
54
+ def generate_bar_plot(planned_cost_inr, actual_spend_inr, forecast_cost_inr):
55
  fig, ax = plt.subplots(figsize=(8, 6))
56
  categories = ['Planned Cost', 'Actual Spend', 'Forecasted Cost']
57
  values = [planned_cost_inr, actual_spend_inr, forecast_cost_inr]
 
83
  plt.close()
84
  return gradio_image, buf_pdf
85
 
86
+ # Function to generate a pie chart for risk distribution
87
+ def generate_pie_chart_data(cost_deviation_factor, material_cost_factor, labor_cost_factor, scope_change_factor):
88
+ labels = ['Cost Deviation', 'Material Cost', 'Labor Cost', 'Scope Change']
89
+ values = [
90
+ max(cost_deviation_factor * 100, 0),
91
+ max(material_cost_factor * 100, 0),
92
+ max(labor_cost_factor * 100, 0),
93
+ max(scope_change_factor * 100, 0)
94
+ ]
95
+ # Ensure at least a small value to display the chart properly
96
+ total = sum(values)
97
+ if total == 0:
98
+ values = [25, 25, 25, 25] # Equal distribution if no risk factors
99
+ return {
100
+ "type": "pie",
101
+ "data": {
102
+ "labels": labels,
103
+ "datasets": [{
104
+ "label": "Risk Distribution",
105
+ "data": values,
106
+ "backgroundColor": ["#FF6384", "#36A2EB", "#FFCE56", "#4BC0C0"],
107
+ "borderColor": ["#FF6384", "#36A2EB", "#FFCE56", "#4BC0C0"],
108
+ "borderWidth": 1
109
+ }]
110
+ },
111
+ "options": {
112
+ "responsive": true,
113
+ "plugins": {
114
+ "legend": {
115
+ "position": "top"
116
+ },
117
+ "title": {
118
+ "display": true,
119
+ "text": "Risk Factor Distribution"
120
+ }
121
+ }
122
+ }
123
+ }
124
+
125
+ # Function to generate a PDF report with red zone styling for critical status
126
+ def generate_pdf(planned_cost_inr, actual_spend_inr, forecast_cost_inr, total_risk, risk_percentage, insights, status, top_causes, category, project_phase, material_cost_index, labor_index, scope_change_impact, alert_message, bar_chart_image):
127
  pdf_path = f"budget_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
128
  c = canvas.Canvas(pdf_path, pagesize=letter)
129
  width, height = letter
 
135
  # Prediction Metrics with Indian formatting
136
  c.setFont("Helvetica", 12)
137
  y_position = height - 100
138
+
139
+ # Apply red zone styling for critical status
140
+ text_color = red if status == "Critical" else black
141
+ c.setFillColor(text_color)
142
+
143
  c.drawString(50, y_position, f"Category: {category}")
144
  y_position -= 20
145
  c.drawString(50, y_position, f"Project Phase: {project_phase}")
 
169
  c.drawString(50, y_position, f"Alert: {alert_message}")
170
  y_position -= 40
171
 
172
+ # Add the bar chart
173
+ chart_reader = ImageReader(bar_chart_image)
174
  c.drawImage(chart_reader, 50, y_position - 300, width=500, height=300)
175
 
176
  c.showPage()
 
220
  try:
221
  planned_cost_inr, actual_spend_inr, line_items = process_uploaded_file(file)
222
  except Exception as e:
223
+ return f"Error processing file: {str(e)}", None, None, None, None, None, None
224
 
225
  # Validate numeric inputs
226
  try:
 
229
  scope_change_impact = float(scope_change_impact) if scope_change_impact else 0
230
  except ValueError:
231
  logger.error("Invalid input: Inputs must be numeric.")
232
+ return "Error: All numeric inputs (material cost index, labor index, scope change impact) must be valid numbers.", None, None, None, None, None, None
233
 
234
  logger.debug(f"Starting prediction with inputs: planned_cost_inr={planned_cost_inr}, actual_spend_inr={actual_spend_inr}, "
235
  f"category={category}, material_cost_index={material_cost_index}, labor_index={labor_index}, "
 
274
  # Check for >10% deviation and generate alert
275
  deviation = ((forecast_cost_inr - planned_cost_inr) / planned_cost_inr * 100) if planned_cost_inr > 0 else 0
276
  alert_message = "Alert: Forecasted cost exceeds planned cost by more than 10%. Notify finance and engineering teams." if deviation > 10 else "No alert triggered."
277
+ alert_style = "background-color: #ffcccc; padding: 10px; border: 1px solid red; border-radius: 5px;" if deviation > 10 else "background-color: #ccffcc; padding: 10px; border: 1px solid green; border-radius: 5px;"
278
 
279
  logger.debug(f"Calculation results: total_risk={total_risk}, risk_percentage={risk_percentage}, forecast_cost_inr={forecast_cost_inr}, "
280
  f"insights={insights}, status={status}, top_causes={top_causes}, alert_message={alert_message}")
281
 
282
+ # Generate the bar chart for Gradio and PDF
283
+ bar_chart_image, bar_chart_image_pdf = generate_bar_plot(planned_cost_inr, actual_spend_inr, forecast_cost_inr)
284
+
285
+ # Generate pie chart for risk distribution
286
+ pie_chart_data = generate_pie_chart_data(cost_deviation_factor, material_cost_factor, labor_cost_factor, scope_change_factor)
287
 
288
  # Generate local PDF report
289
+ pdf_file = generate_pdf(planned_cost_inr, actual_spend_inr, forecast_cost_inr, total_risk, risk_percentage, insights, status, top_causes, category, project_phase, material_cost_index, labor_index, scope_change_impact, alert_message, bar_chart_image_pdf)
290
 
291
  # Generate Excel file
292
  excel_file = generate_excel(planned_cost_inr, actual_spend_inr, forecast_cost_inr, total_risk, risk_percentage, insights, status, top_causes, category, project_phase, material_cost_index, labor_index, scope_change_impact, alert_message)
 
299
  f"Risk Level: {risk_level}\n"
300
  f"Risk Percentage: {risk_percentage}%\n"
301
  f"Status: {status}\n"
302
+ f"Insights: {insights} due to {top_causes.lower()}.\n\n"
 
303
  f"Project Details\n"
304
  f"----------------------------------------\n"
305
  f"Category: {category}\n"
 
309
  f"Scope Change Impact: {scope_change_impact}%\n\n"
310
  f"Forecast Chart\n"
311
  f"----------------------------------------\n"
312
+ f"[Bar chart displayed below]\n\n"
313
  f"Detailed Metrics\n"
314
  f"----------------------------------------\n"
315
  f"Total Risk: {total_risk}\n"
 
320
  f"Local PDF Report: [Download link below]\n"
321
  f"Excel Report: [Download link below]"
322
  )
323
+
324
+ # Dashboard content (simplified risk level display)
325
+ dashboard_content = f"**Risk Level for {category}: {risk_level} ({risk_percentage}%)**"
326
+
327
+ return output_text, bar_chart_image, pie_chart_data, pdf_file, excel_file, f"<div style='{alert_style}'>{alert_message}</div>", dashboard_content
328
 
329
  # Function to update Material Cost Index explanation based on category
330
  def update_material_cost_explanation(category):
 
361
  f"A value above 150 flags a potential risk. Example: If the index is 160, labor costs are 60% higher than the baseline."
362
  )
363
 
364
+ # Custom CSS for the golden button and alert card
365
  custom_css = """
366
  #submit-button {
367
  background-color: #FFD700 !important; /* Golden background */
 
383
  # Custom Gradio Blocks interface
384
  with gr.Blocks(title="Budget Overrun Risk Estimator", css=custom_css) as demo:
385
  gr.Markdown("# Budget Overrun Risk Estimator")
386
+ gr.Markdown("Upload a CSV file with budget line items (columns: 'Planned_Cost', 'Actual_Spend') to estimate budget overrun risk. All numeric fields are required.")
387
 
388
  with gr.Row():
389
  with gr.Column():
 
405
  submit_button = gr.Button("Submit", elem_id="submit-button")
406
 
407
  with gr.Column():
408
+ gr.Markdown("## Dashboard")
409
+ dashboard_output = gr.Markdown(label="Risk Level Dashboard")
410
+
411
+ gr.Markdown("## Prediction Results")
412
  output_text = gr.Textbox(label="Prediction Results", lines=20, max_lines=30)
413
+
414
+ gr.Markdown("## Forecast Chart")
415
+ bar_chart_output = gr.Image(label="Budget Overview (Bar Chart)")
416
+
417
+ gr.Markdown("## Risk Distribution")
418
+ pie_chart_output = gr.Plot(label="Risk Factor Distribution (Pie Chart)")
419
+
420
+ gr.Markdown("## Alerts")
421
+ alert_output = gr.HTML(label="Alert Notification")
422
+
423
  output_pdf = gr.File(label="Download Local PDF Report")
424
  output_excel = gr.File(label="Download Excel Report")
425
 
 
437
 
438
  # Clear button functionality
439
  clear_button.click(
440
+ fn=lambda: (None, "Plumbing", "", "", "", "Planning", "", None, None, None, "", ""),
441
  outputs=[
442
  file_input, category_input, material_cost_input, labor_index_input,
443
+ scope_change_input, project_phase_input, output_text, bar_chart_output,
444
+ pie_chart_output, output_pdf, output_excel, alert_output, dashboard_output
445
  ]
446
  )
447
 
 
449
  submit_button.click(
450
  fn=predict_risk,
451
  inputs=[file_input, category_input, material_cost_input, labor_index_input, scope_change_input, project_phase_input],
452
+ outputs=[output_text, bar_chart_output, pie_chart_output, output_pdf, output_excel, alert_output, dashboard_output]
453
  )
454
 
455
  # Launch the app