Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -10,16 +10,37 @@ from reportlab.lib.styles import getSampleStyleSheet
|
|
| 10 |
from reportlab.lib.units import inch
|
| 11 |
from io import BytesIO
|
| 12 |
from simple_salesforce import Salesforce
|
| 13 |
-
import os
|
| 14 |
|
| 15 |
-
#
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
-
# Initialize
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
# Function to format high_risk_phases with flag and alert
|
| 25 |
def format_high_risk_phases(high_risk_phases):
|
|
@@ -63,7 +84,6 @@ def generate_pdf(input_data, prediction, heatmap_fig):
|
|
| 63 |
|
| 64 |
# Prediction Results
|
| 65 |
story.append(Paragraph("Prediction Results", styles['Heading2']))
|
| 66 |
-
# Format high_risk_phases for PDF
|
| 67 |
high_risk_text = "<br/>".join(format_high_risk_phases(prediction['high_risk_phases']))
|
| 68 |
prediction_fields = [
|
| 69 |
f"Delay Probability: {prediction['delay_probability']:.2f}%",
|
|
@@ -77,65 +97,45 @@ def generate_pdf(input_data, prediction, heatmap_fig):
|
|
| 77 |
|
| 78 |
# Heatmap
|
| 79 |
story.append(Paragraph("Delay Risk Heatmap", styles['Heading2']))
|
| 80 |
-
# Save heatmap figure to BytesIO as PNG
|
| 81 |
img_buffer = BytesIO()
|
| 82 |
heatmap_fig.savefig(img_buffer, format='png', bbox_inches='tight')
|
| 83 |
img_buffer.seek(0)
|
| 84 |
-
# Embed image in PDF (scale to fit page width)
|
| 85 |
story.append(Image(img_buffer, width=6*inch, height=2*inch))
|
| 86 |
-
plt.close(heatmap_fig)
|
| 87 |
|
| 88 |
doc.build(story)
|
| 89 |
buffer.seek(0)
|
| 90 |
return buffer
|
| 91 |
|
| 92 |
-
# Function to save data
|
| 93 |
def save_to_salesforce(input_data, prediction):
|
|
|
|
|
|
|
| 94 |
try:
|
| 95 |
-
#
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
}
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
print("Record saved to Salesforce successfully!")
|
| 118 |
except Exception as e:
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
# Streamlit app configuration
|
| 122 |
-
st.set_page_config(page_title="Delay 🚀", layout="wide")
|
| 123 |
-
|
| 124 |
-
# Title
|
| 125 |
-
st.title("Project Delay Predictor 🚀")
|
| 126 |
-
|
| 127 |
-
# Task options per phase
|
| 128 |
-
task_options = {
|
| 129 |
-
"Planning": ["Define Scope", "Resource Allocation", "Permit Acquisition"],
|
| 130 |
-
"Design": ["Architectural Drafting", "Engineering Analysis", "Design Review"],
|
| 131 |
-
"Construction": ["Foundation Work", "Structural Build", "Utility Installation"]
|
| 132 |
-
}
|
| 133 |
-
|
| 134 |
-
# Initialize session state for phase and task
|
| 135 |
-
if 'phase' not in st.session_state:
|
| 136 |
-
st.session_state.phase = ""
|
| 137 |
-
if 'task' not in st.session_state:
|
| 138 |
-
st.session_state.task = ""
|
| 139 |
|
| 140 |
# Input form
|
| 141 |
with st.form("project_form"):
|
|
@@ -145,10 +145,9 @@ with st.form("project_form"):
|
|
| 145 |
project_name = st.text_input("Project Name")
|
| 146 |
phase = st.selectbox("Phase", [""] + ["Planning", "Design", "Construction"], index=0, key="phase_select")
|
| 147 |
|
| 148 |
-
# Update task options based on phase
|
| 149 |
if phase != st.session_state.phase:
|
| 150 |
st.session_state.phase = phase
|
| 151 |
-
st.session_state.task = ""
|
| 152 |
task_options_list = [""] + task_options.get(phase, []) if phase else [""]
|
| 153 |
task = st.selectbox("Task", task_options_list, index=0, key="task_select")
|
| 154 |
current_progress = st.number_input("Current Progress (%)", min_value=0.0, max_value=100.0, step=1.0)
|
|
@@ -159,10 +158,8 @@ with st.form("project_form"):
|
|
| 159 |
workforce_gap = st.number_input("Workforce Gap (%)", min_value=0.0, max_value=100.0, step=1.0)
|
| 160 |
workforce_skill_level = st.selectbox("Workforce Skill Level", ["Low", "Medium", "High"], index=1)
|
| 161 |
workforce_shift_hours = st.number_input("Workforce Shift Hours", min_value=0, step=1, value=8)
|
| 162 |
-
# Debug output for shift hours
|
| 163 |
st.write(f"**Selected Shift Hours**: {workforce_shift_hours}")
|
| 164 |
weather_impact_score = st.number_input("Weather Impact Score (0-100)", min_value=0, max_value=100, step=1)
|
| 165 |
-
# Display computed weather condition
|
| 166 |
weather_condition = get_weather_condition(weather_impact_score)
|
| 167 |
st.write(f"**Weather Condition**: {weather_condition}")
|
| 168 |
weather_forecast_date = st.date_input("Weather Forecast Date", min_value=datetime(2025, 1, 1))
|
|
@@ -171,7 +168,6 @@ with st.form("project_form"):
|
|
| 171 |
|
| 172 |
# Process form submission
|
| 173 |
if submit_button:
|
| 174 |
-
# Prepare input data
|
| 175 |
input_data = {
|
| 176 |
"project_name": project_name,
|
| 177 |
"phase": phase,
|
|
@@ -187,19 +183,16 @@ if submit_button:
|
|
| 187 |
"weather_forecast_date": weather_forecast_date.strftime("%Y-%m-%d")
|
| 188 |
}
|
| 189 |
|
| 190 |
-
# Validate inputs
|
| 191 |
error = validate_inputs(input_data)
|
| 192 |
if error:
|
| 193 |
st.error(error)
|
| 194 |
else:
|
| 195 |
-
# Get prediction
|
| 196 |
with st.spinner("Predicting..."):
|
| 197 |
prediction = predict_delay(input_data)
|
| 198 |
|
| 199 |
if "error" in prediction:
|
| 200 |
st.error(prediction["error"])
|
| 201 |
else:
|
| 202 |
-
# Display results
|
| 203 |
st.subheader("Prediction Results")
|
| 204 |
st.write(f"**Delay Probability**: {prediction['delay_probability']:.2f}%")
|
| 205 |
st.write("**High Risk Phases**:")
|
|
@@ -208,14 +201,9 @@ if submit_button:
|
|
| 208 |
st.write(f"**AI Insights**: {prediction['ai_insights']}")
|
| 209 |
st.write(f"**Weather Condition**: {prediction['weather_condition']}")
|
| 210 |
|
| 211 |
-
# Generate and display heatmap
|
| 212 |
fig = generate_heatmap(prediction['delay_probability'], f"{phase}: {task}")
|
| 213 |
st.pyplot(fig)
|
| 214 |
|
| 215 |
-
# Save to Salesforce after prediction
|
| 216 |
-
save_to_salesforce(input_data, prediction)
|
| 217 |
-
|
| 218 |
-
# Generate PDF with heatmap and provide download link
|
| 219 |
pdf_buffer = generate_pdf(input_data, prediction, fig)
|
| 220 |
st.download_button(
|
| 221 |
label="Download Prediction Report (PDF)",
|
|
@@ -224,6 +212,12 @@ if submit_button:
|
|
| 224 |
mime="application/pdf"
|
| 225 |
)
|
| 226 |
|
| 227 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
st.session_state.prediction = prediction
|
| 229 |
-
st.session_state.input_data = input_data
|
|
|
|
| 10 |
from reportlab.lib.units import inch
|
| 11 |
from io import BytesIO
|
| 12 |
from simple_salesforce import Salesforce
|
|
|
|
| 13 |
|
| 14 |
+
# Streamlit app configuration
|
| 15 |
+
st.set_page_config(page_title="Delay 🚀", layout="wide")
|
| 16 |
+
|
| 17 |
+
# Salesforce connection (using Streamlit secrets)
|
| 18 |
+
try:
|
| 19 |
+
sf = Salesforce(
|
| 20 |
+
username=st.secrets["SF_USERNAME"],
|
| 21 |
+
password=st.secrets["SF_PASSWORD"],
|
| 22 |
+
security_token=st.secrets["SF_SECURITY_TOKEN"],
|
| 23 |
+
instance_url=st.secrets["SF_INSTANCE_URL"]
|
| 24 |
+
)
|
| 25 |
+
except Exception as e:
|
| 26 |
+
st.error(f"Failed to connect to Salesforce: {str(e)}")
|
| 27 |
+
sf = None
|
| 28 |
+
|
| 29 |
+
# Title
|
| 30 |
+
st.title("Project Delay Predictor 🚀")
|
| 31 |
+
|
| 32 |
+
# Task options per phase
|
| 33 |
+
task_options = {
|
| 34 |
+
"Planning": ["Define Scope", "Resource Allocation", "Permit Acquisition"],
|
| 35 |
+
"Design": ["Architectural Drafting", "Engineering Analysis", "Design Review"],
|
| 36 |
+
"Construction": ["Foundation Work", "Structural Build", "Utility Installation"]
|
| 37 |
+
}
|
| 38 |
|
| 39 |
+
# Initialize session state for phase and task
|
| 40 |
+
if 'phase' not in st.session_state:
|
| 41 |
+
st.session_state.phase = ""
|
| 42 |
+
if 'task' not in st.session_state:
|
| 43 |
+
st.session_state.task = ""
|
| 44 |
|
| 45 |
# Function to format high_risk_phases with flag and alert
|
| 46 |
def format_high_risk_phases(high_risk_phases):
|
|
|
|
| 84 |
|
| 85 |
# Prediction Results
|
| 86 |
story.append(Paragraph("Prediction Results", styles['Heading2']))
|
|
|
|
| 87 |
high_risk_text = "<br/>".join(format_high_risk_phases(prediction['high_risk_phases']))
|
| 88 |
prediction_fields = [
|
| 89 |
f"Delay Probability: {prediction['delay_probability']:.2f}%",
|
|
|
|
| 97 |
|
| 98 |
# Heatmap
|
| 99 |
story.append(Paragraph("Delay Risk Heatmap", styles['Heading2']))
|
|
|
|
| 100 |
img_buffer = BytesIO()
|
| 101 |
heatmap_fig.savefig(img_buffer, format='png', bbox_inches='tight')
|
| 102 |
img_buffer.seek(0)
|
|
|
|
| 103 |
story.append(Image(img_buffer, width=6*inch, height=2*inch))
|
| 104 |
+
plt.close(heatmap_fig)
|
| 105 |
|
| 106 |
doc.build(story)
|
| 107 |
buffer.seek(0)
|
| 108 |
return buffer
|
| 109 |
|
| 110 |
+
# Function to save data to Salesforce
|
| 111 |
def save_to_salesforce(input_data, prediction):
|
| 112 |
+
if sf is None:
|
| 113 |
+
return "Salesforce connection not established."
|
| 114 |
try:
|
| 115 |
+
# Prepare data for Delay_Predictor__c object
|
| 116 |
+
sf_data = {
|
| 117 |
+
"Project_Name__c": input_data["project_name"],
|
| 118 |
+
"Phase__c": input_data["phase"],
|
| 119 |
+
"Task__c": input_data["task"],
|
| 120 |
+
"Current_Progress__c": input_data["current_progress"],
|
| 121 |
+
"Task_Expected_Duration__c": input_data["task_expected_duration"],
|
| 122 |
+
"Task_Actual_Duration__c": input_data["task_actual_duration"],
|
| 123 |
+
"Workforce_Gap__c": input_data["workforce_gap"],
|
| 124 |
+
"Workforce_Skill_Level__c": input_data["workforce_skill_level"],
|
| 125 |
+
"Workforce_Shift_Hours__c": input_data["workforce_shift_hours"],
|
| 126 |
+
"Weather_Impact_Score__c": input_data["weather_impact_score"],
|
| 127 |
+
"Weather_Condition__c": input_data["weather_condition"],
|
| 128 |
+
"Weather_Forecast_Date__c": input_data["weather_forecast_date"],
|
| 129 |
+
"Delay_Probability__c": prediction["delay_probability"],
|
| 130 |
+
"AI_Insights__c": prediction["ai_insights"],
|
| 131 |
+
# Store high_risk_phases as a formatted string
|
| 132 |
+
"High_Risk_Phases__c": "; ".join(format_high_risk_phases(prediction["high_risk_phases"]))
|
| 133 |
}
|
| 134 |
+
# Create a new record in Delay_Predictor__c
|
| 135 |
+
result = sf.Delay_Predictor__c.create(sf_data)
|
| 136 |
+
return None if result["success"] else f"Salesforce save failed: {result['errors']}"
|
|
|
|
| 137 |
except Exception as e:
|
| 138 |
+
return f"Error saving to Salesforce: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
# Input form
|
| 141 |
with st.form("project_form"):
|
|
|
|
| 145 |
project_name = st.text_input("Project Name")
|
| 146 |
phase = st.selectbox("Phase", [""] + ["Planning", "Design", "Construction"], index=0, key="phase_select")
|
| 147 |
|
|
|
|
| 148 |
if phase != st.session_state.phase:
|
| 149 |
st.session_state.phase = phase
|
| 150 |
+
st.session_state.task = ""
|
| 151 |
task_options_list = [""] + task_options.get(phase, []) if phase else [""]
|
| 152 |
task = st.selectbox("Task", task_options_list, index=0, key="task_select")
|
| 153 |
current_progress = st.number_input("Current Progress (%)", min_value=0.0, max_value=100.0, step=1.0)
|
|
|
|
| 158 |
workforce_gap = st.number_input("Workforce Gap (%)", min_value=0.0, max_value=100.0, step=1.0)
|
| 159 |
workforce_skill_level = st.selectbox("Workforce Skill Level", ["Low", "Medium", "High"], index=1)
|
| 160 |
workforce_shift_hours = st.number_input("Workforce Shift Hours", min_value=0, step=1, value=8)
|
|
|
|
| 161 |
st.write(f"**Selected Shift Hours**: {workforce_shift_hours}")
|
| 162 |
weather_impact_score = st.number_input("Weather Impact Score (0-100)", min_value=0, max_value=100, step=1)
|
|
|
|
| 163 |
weather_condition = get_weather_condition(weather_impact_score)
|
| 164 |
st.write(f"**Weather Condition**: {weather_condition}")
|
| 165 |
weather_forecast_date = st.date_input("Weather Forecast Date", min_value=datetime(2025, 1, 1))
|
|
|
|
| 168 |
|
| 169 |
# Process form submission
|
| 170 |
if submit_button:
|
|
|
|
| 171 |
input_data = {
|
| 172 |
"project_name": project_name,
|
| 173 |
"phase": phase,
|
|
|
|
| 183 |
"weather_forecast_date": weather_forecast_date.strftime("%Y-%m-%d")
|
| 184 |
}
|
| 185 |
|
|
|
|
| 186 |
error = validate_inputs(input_data)
|
| 187 |
if error:
|
| 188 |
st.error(error)
|
| 189 |
else:
|
|
|
|
| 190 |
with st.spinner("Predicting..."):
|
| 191 |
prediction = predict_delay(input_data)
|
| 192 |
|
| 193 |
if "error" in prediction:
|
| 194 |
st.error(prediction["error"])
|
| 195 |
else:
|
|
|
|
| 196 |
st.subheader("Prediction Results")
|
| 197 |
st.write(f"**Delay Probability**: {prediction['delay_probability']:.2f}%")
|
| 198 |
st.write("**High Risk Phases**:")
|
|
|
|
| 201 |
st.write(f"**AI Insights**: {prediction['ai_insights']}")
|
| 202 |
st.write(f"**Weather Condition**: {prediction['weather_condition']}")
|
| 203 |
|
|
|
|
| 204 |
fig = generate_heatmap(prediction['delay_probability'], f"{phase}: {task}")
|
| 205 |
st.pyplot(fig)
|
| 206 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
pdf_buffer = generate_pdf(input_data, prediction, fig)
|
| 208 |
st.download_button(
|
| 209 |
label="Download Prediction Report (PDF)",
|
|
|
|
| 212 |
mime="application/pdf"
|
| 213 |
)
|
| 214 |
|
| 215 |
+
# Save to Salesforce
|
| 216 |
+
sf_error = save_to_salesforce(input_data, prediction)
|
| 217 |
+
if sf_error:
|
| 218 |
+
st.error(sf_error)
|
| 219 |
+
else:
|
| 220 |
+
st.success("Prediction data successfully saved to Salesforce!")
|
| 221 |
+
|
| 222 |
st.session_state.prediction = prediction
|
| 223 |
+
st.session_state.input_data = input_data
|