Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -57,7 +57,7 @@ project_choices = [
|
|
| 57 |
"Project Alpha", "Project Beta", "Project Gamma", "Project Delta", "Project Epsilon",
|
| 58 |
"Project Zeta", "Project Theta", "Project Sigma", "Project Omega", "Project Phoenix"
|
| 59 |
]
|
| 60 |
-
ai_suggestion_choices = ["Move", "Repair", "Replace"]
|
| 61 |
|
| 62 |
def validate_date(last_maint):
|
| 63 |
try:
|
|
@@ -83,6 +83,7 @@ def call_ai_model(usage, idle, freq, cost, last):
|
|
| 83 |
utilization_ratio = usage / total if total > 0 else 0.0
|
| 84 |
utilization_percent = utilization_ratio * 100
|
| 85 |
|
|
|
|
| 86 |
if utilization_percent < 60:
|
| 87 |
sug = "Move"
|
| 88 |
elif utilization_percent < 80:
|
|
@@ -99,6 +100,7 @@ def call_ai_model(usage, idle, freq, cost, last):
|
|
| 99 |
base_conf *= (0.7 + 0.3 * freq_factor)
|
| 100 |
confidence = max(0.05, min(base_conf, 1.0))
|
| 101 |
|
|
|
|
| 102 |
return sug, round(confidence, 2), round(utilization_percent, 2)
|
| 103 |
|
| 104 |
except Exception as e:
|
|
@@ -110,10 +112,13 @@ def process_equipment_utilization(equip, proj, use_h, idle_h, move_f, cost_h, la
|
|
| 110 |
if not sf:
|
| 111 |
raise ValueError("Salesforce connection is not initialized. Please check credentials and try again.")
|
| 112 |
|
|
|
|
| 113 |
last_maint = validate_date(last_maint)
|
| 114 |
|
|
|
|
| 115 |
ai_sug_generated, conf, score = call_ai_model(use_h, idle_h, move_f, cost_h, last_maint)
|
| 116 |
|
|
|
|
| 117 |
suggestion_to_use = ai_sug if ai_sug else ai_sug_generated
|
| 118 |
|
| 119 |
for field, value in [("Usage Hours", use_h), ("Idle Hours", idle_h),
|
|
@@ -131,7 +136,7 @@ def process_equipment_utilization(equip, proj, use_h, idle_h, move_f, cost_h, la
|
|
| 131 |
"Usage Hours": use_h,
|
| 132 |
"Idle Hours": idle_h,
|
| 133 |
"Suggestion": suggestion_to_use,
|
| 134 |
-
"Confidence": conf * 100,
|
| 135 |
"Utilization Score": score,
|
| 136 |
"Cost per Hour": cost_h,
|
| 137 |
"Last Maintenance": last_maint or "N/A"
|
|
@@ -204,28 +209,49 @@ def process_equipment_utilization(equip, proj, use_h, idle_h, move_f, cost_h, la
|
|
| 204 |
logger.error(f"Error in process_equipment_utilization: {e}")
|
| 205 |
raise ValueError(f"Processing failed: {str(e)}")
|
| 206 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
def format_batch_output(records):
|
| 208 |
lines = []
|
| 209 |
for i, rec in enumerate(records, 1):
|
| 210 |
summary = rec.get("Summary", {})
|
| 211 |
|
| 212 |
-
#
|
| 213 |
record_details = [
|
| 214 |
-
f"Record {i}:
|
| 215 |
-
f"
|
| 216 |
-
f"Equipment Name: {summary.get('Equipment Name', 'N/A')}",
|
| 217 |
-
f"Project: {summary.get('Project', 'N/A')}",
|
| 218 |
-
f"Usage Hours: {summary.get('Usage Hours', 0):.2f}",
|
| 219 |
-
f"Idle Hours: {summary.get('Idle Hours', 0):.2f}",
|
| 220 |
-
f"Suggestion: {summary.get('Suggestion', 'N/A')}",
|
| 221 |
-
f"Confidence: {summary.get('Confidence', 0):.2f}",
|
| 222 |
-
f"Utilization Score: {summary.get('Utilization Score', 0):.2f}",
|
| 223 |
-
f"Cost per Hour: βΉ{summary.get('Cost per Hour', 0):,.2f}",
|
| 224 |
-
f"Last Maintenance: {summary.get('Last Maintenance', 'N/A')}"
|
| 225 |
]
|
| 226 |
lines.append("\n".join(record_details))
|
| 227 |
lines.append("\n---\n") # Separator between records
|
| 228 |
-
|
| 229 |
return "\n".join(lines)
|
| 230 |
|
| 231 |
def generate_batch_pdf(records, batch_uid):
|
|
@@ -382,7 +408,7 @@ with gr.Blocks() as app:
|
|
| 382 |
submit_btn.click(
|
| 383 |
fn=manual_input,
|
| 384 |
inputs=[equipment_dropdown, project_dropdown, usage, idle, freq, cost, last, ai_dropdown],
|
| 385 |
-
outputs=[result_txt, report_file]
|
| 386 |
)
|
| 387 |
clear_btn.click(lambda: ("", None), None, [result_txt, report_file])
|
| 388 |
with gr.TabItem("CSV Upload"):
|
|
@@ -391,7 +417,7 @@ with gr.Blocks() as app:
|
|
| 391 |
with gr.Row():
|
| 392 |
upload_btn = gr.Button("π Upload", variant="primary")
|
| 393 |
clear_btn = gr.Button("π§Ή Clear")
|
| 394 |
-
csv_output = gr.Markdown(label="π Batch Upload Results")
|
| 395 |
batch_pdf = gr.File(label="π Download Batch PDF Report", file_types=[".pdf"])
|
| 396 |
upload_btn.click(
|
| 397 |
fn=batch_upload,
|
|
@@ -399,7 +425,7 @@ with gr.Blocks() as app:
|
|
| 399 |
outputs=[csv_output, batch_pdf]
|
| 400 |
)
|
| 401 |
clear_btn.click(
|
| 402 |
-
lambda: (None, "", None),
|
| 403 |
None,
|
| 404 |
[csv_file, csv_output, batch_pdf]
|
| 405 |
)
|
|
@@ -410,4 +436,4 @@ with gr.Blocks() as app:
|
|
| 410 |
#result-box { border: 3px solid #d3d3d3 !important; border-radius: 10px; padding: 10px; background: #f9f9f9; white-space: pre-line; }
|
| 411 |
"""
|
| 412 |
if __name__ == "__main__":
|
| 413 |
-
app.launch()
|
|
|
|
| 57 |
"Project Alpha", "Project Beta", "Project Gamma", "Project Delta", "Project Epsilon",
|
| 58 |
"Project Zeta", "Project Theta", "Project Sigma", "Project Omega", "Project Phoenix"
|
| 59 |
]
|
| 60 |
+
ai_suggestion_choices = ["Move", "Repair", "Replace"] # Removed "Pause Rent"
|
| 61 |
|
| 62 |
def validate_date(last_maint):
|
| 63 |
try:
|
|
|
|
| 83 |
utilization_ratio = usage / total if total > 0 else 0.0
|
| 84 |
utilization_percent = utilization_ratio * 100
|
| 85 |
|
| 86 |
+
# Determine suggestion (no "Pause Rent")
|
| 87 |
if utilization_percent < 60:
|
| 88 |
sug = "Move"
|
| 89 |
elif utilization_percent < 80:
|
|
|
|
| 100 |
base_conf *= (0.7 + 0.3 * freq_factor)
|
| 101 |
confidence = max(0.05, min(base_conf, 1.0))
|
| 102 |
|
| 103 |
+
# Round before return
|
| 104 |
return sug, round(confidence, 2), round(utilization_percent, 2)
|
| 105 |
|
| 106 |
except Exception as e:
|
|
|
|
| 112 |
if not sf:
|
| 113 |
raise ValueError("Salesforce connection is not initialized. Please check credentials and try again.")
|
| 114 |
|
| 115 |
+
# Validate the Last Maintenance date
|
| 116 |
last_maint = validate_date(last_maint)
|
| 117 |
|
| 118 |
+
# Always run AI model to get suggestion, confidence, score
|
| 119 |
ai_sug_generated, conf, score = call_ai_model(use_h, idle_h, move_f, cost_h, last_maint)
|
| 120 |
|
| 121 |
+
# Use manual suggestion if provided, else AI suggestion
|
| 122 |
suggestion_to_use = ai_sug if ai_sug else ai_sug_generated
|
| 123 |
|
| 124 |
for field, value in [("Usage Hours", use_h), ("Idle Hours", idle_h),
|
|
|
|
| 136 |
"Usage Hours": use_h,
|
| 137 |
"Idle Hours": idle_h,
|
| 138 |
"Suggestion": suggestion_to_use,
|
| 139 |
+
"Confidence": conf * 100, # Store as percentage (0-100)
|
| 140 |
"Utilization Score": score,
|
| 141 |
"Cost per Hour": cost_h,
|
| 142 |
"Last Maintenance": last_maint or "N/A"
|
|
|
|
| 209 |
logger.error(f"Error in process_equipment_utilization: {e}")
|
| 210 |
raise ValueError(f"Processing failed: {str(e)}")
|
| 211 |
|
| 212 |
+
def format_output(result):
|
| 213 |
+
summary = result.get("Summary", {})
|
| 214 |
+
cost_val = summary.get("Cost per Hour", 0)
|
| 215 |
+
try:
|
| 216 |
+
cost_str = locale.currency(cost_val, grouping=True)
|
| 217 |
+
except:
|
| 218 |
+
cost_str = f"βΉ{cost_val:,.2f}"
|
| 219 |
+
conf_pct = summary.get("Confidence", 0) # Already percentage (0-100)
|
| 220 |
+
util_score = summary.get("Utilization Score", 0) # Already percentage (0-100)
|
| 221 |
+
lines = [
|
| 222 |
+
f" β’ AI Suggestion: {summary.get('Suggestion', 'N/A')}",
|
| 223 |
+
f" β’ Suggestion Confidence: {conf_pct:.2f}%",
|
| 224 |
+
f" β’ Utilization Score: {util_score:.2f}%",
|
| 225 |
+
f" β’ Equipment Name: {summary.get('Equipment Name', 'N/A')}",
|
| 226 |
+
f" β’ Project: {summary.get('Project', 'N/A')}",
|
| 227 |
+
f" β’ Usage Hours: {summary.get('Usage Hours', 0):.2f}",
|
| 228 |
+
f" β’ Idle Hours: {summary.get('Idle Hours', 0):.2f}",
|
| 229 |
+
f" β’ Cost per Hour: {cost_str}",
|
| 230 |
+
f" β’ Last Maintenance: {summary.get('Last Maintenance', 'N/A')}"
|
| 231 |
+
]
|
| 232 |
+
return "\n".join(lines)
|
| 233 |
+
|
| 234 |
def format_batch_output(records):
|
| 235 |
lines = []
|
| 236 |
for i, rec in enumerate(records, 1):
|
| 237 |
summary = rec.get("Summary", {})
|
| 238 |
|
| 239 |
+
# Detailed record output format
|
| 240 |
record_details = [
|
| 241 |
+
f"Record {i}:",
|
| 242 |
+
f" β’ Record ID: {rec['Salesforce_Record_Id']}",
|
| 243 |
+
f" β’ Equipment Name: {summary.get('Equipment Name', 'N/A')}",
|
| 244 |
+
f" β’ Project: {summary.get('Project', 'N/A')}",
|
| 245 |
+
f" β’ Usage Hours: {summary.get('Usage Hours', 0):.2f}",
|
| 246 |
+
f" β’ Idle Hours: {summary.get('Idle Hours', 0):.2f}",
|
| 247 |
+
f" β’ Suggestion: {summary.get('Suggestion', 'N/A')}",
|
| 248 |
+
f" β’ Suggestion Confidence: {summary.get('Confidence', 0):.2f}%",
|
| 249 |
+
f" β’ Utilization Score: {summary.get('Utilization Score', 0):.2f}%",
|
| 250 |
+
f" β’ Cost per Hour: βΉ{summary.get('Cost per Hour', 0):,.2f}",
|
| 251 |
+
f" β’ Last Maintenance: {summary.get('Last Maintenance', 'N/A')}"
|
| 252 |
]
|
| 253 |
lines.append("\n".join(record_details))
|
| 254 |
lines.append("\n---\n") # Separator between records
|
|
|
|
| 255 |
return "\n".join(lines)
|
| 256 |
|
| 257 |
def generate_batch_pdf(records, batch_uid):
|
|
|
|
| 408 |
submit_btn.click(
|
| 409 |
fn=manual_input,
|
| 410 |
inputs=[equipment_dropdown, project_dropdown, usage, idle, freq, cost, last, ai_dropdown],
|
| 411 |
+
outputs=[result_txt, report_file] # Only PDF output here now
|
| 412 |
)
|
| 413 |
clear_btn.click(lambda: ("", None), None, [result_txt, report_file])
|
| 414 |
with gr.TabItem("CSV Upload"):
|
|
|
|
| 417 |
with gr.Row():
|
| 418 |
upload_btn = gr.Button("π Upload", variant="primary")
|
| 419 |
clear_btn = gr.Button("π§Ή Clear")
|
| 420 |
+
csv_output = gr.Markdown(label="π Batch Upload Results", elem_id="result-box")
|
| 421 |
batch_pdf = gr.File(label="π Download Batch PDF Report", file_types=[".pdf"])
|
| 422 |
upload_btn.click(
|
| 423 |
fn=batch_upload,
|
|
|
|
| 425 |
outputs=[csv_output, batch_pdf]
|
| 426 |
)
|
| 427 |
clear_btn.click(
|
| 428 |
+
lambda: (None, "", None), # Reset file input, output markdown, and pdf file output
|
| 429 |
None,
|
| 430 |
[csv_file, csv_output, batch_pdf]
|
| 431 |
)
|
|
|
|
| 436 |
#result-box { border: 3px solid #d3d3d3 !important; border-radius: 10px; padding: 10px; background: #f9f9f9; white-space: pre-line; }
|
| 437 |
"""
|
| 438 |
if __name__ == "__main__":
|
| 439 |
+
app.launch()
|