Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -6,24 +6,23 @@ import io
|
|
| 6 |
|
| 7 |
st.set_page_config(page_title="Construction Estimator", layout="centered")
|
| 8 |
|
| 9 |
-
def calculate_scaled_quantities(base_qty_df, covered_area):
|
| 10 |
"""
|
| 11 |
base_qty_df: DataFrame with columns: Material, Unit, Quantity_per_1000sqft
|
| 12 |
covered_area: float, in sqft
|
|
|
|
| 13 |
|
| 14 |
-
Returns a DataFrame with scaled quantities according to covered area
|
| 15 |
"""
|
| 16 |
scale_factor = covered_area / 1000
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
return base_qty_df
|
| 19 |
|
| 20 |
def calculate_costs(qty_df, rates_df):
|
| 21 |
-
"""
|
| 22 |
-
qty_df: DataFrame with scaled quantities (Material, Unit, Scaled Quantity)
|
| 23 |
-
rates_df: DataFrame with columns: Material, Unit, Rate_per_Unit
|
| 24 |
-
|
| 25 |
-
Returns a DataFrame with cost calculations
|
| 26 |
-
"""
|
| 27 |
df = pd.merge(qty_df, rates_df, on=['Material', 'Unit'], how='left')
|
| 28 |
df['Amount'] = df['Scaled Quantity'] * df['Rate_per_Unit']
|
| 29 |
df.fillna({'Rate_per_Unit':0, 'Amount':0}, inplace=True)
|
|
@@ -73,9 +72,9 @@ def draw_floor_plan(rooms, baths, living, car_porch, covered_area):
|
|
| 73 |
return buf
|
| 74 |
|
| 75 |
def main():
|
| 76 |
-
st.title("🧱 Construction Material Estimator")
|
| 77 |
|
| 78 |
-
st.markdown("Upload **Base Quantities per 1000 sqft** and **Material Rates** Excel files. Then enter project details
|
| 79 |
|
| 80 |
qty_file = st.file_uploader("Upload Base Quantities Excel (Material, Unit, Quantity_per_1000sqft)", type=["xlsx", "xls"])
|
| 81 |
rate_file = st.file_uploader("Upload Material Rates Excel (Material, Unit, Rate_per_Unit)", type=["xlsx", "xls"])
|
|
@@ -85,7 +84,6 @@ def main():
|
|
| 85 |
qty_df = pd.read_excel(qty_file)
|
| 86 |
rate_df = pd.read_excel(rate_file)
|
| 87 |
|
| 88 |
-
# Validate expected columns
|
| 89 |
required_qty_cols = {'Material', 'Unit', 'Quantity_per_1000sqft'}
|
| 90 |
required_rate_cols = {'Material', 'Unit', 'Rate_per_Unit'}
|
| 91 |
|
|
@@ -97,13 +95,14 @@ def main():
|
|
| 97 |
return
|
| 98 |
|
| 99 |
covered_area = st.number_input("Covered Area (sqft)", min_value=100, value=1200)
|
|
|
|
| 100 |
rooms = st.number_input("Number of Rooms", min_value=0, value=3)
|
| 101 |
baths = st.number_input("Number of Bathrooms", min_value=0, value=2)
|
| 102 |
living = st.number_input("Number of Living Rooms", min_value=0, value=1)
|
| 103 |
car_porch = st.number_input("Number of Car Porches", min_value=0, value=1)
|
| 104 |
|
| 105 |
if st.button("Calculate BOQ & Cost"):
|
| 106 |
-
scaled_qty_df = calculate_scaled_quantities(qty_df, covered_area)
|
| 107 |
cost_df = calculate_costs(scaled_qty_df, rate_df)
|
| 108 |
boq_table = generate_boq_table(cost_df)
|
| 109 |
|
|
|
|
| 6 |
|
| 7 |
st.set_page_config(page_title="Construction Estimator", layout="centered")
|
| 8 |
|
| 9 |
+
def calculate_scaled_quantities(base_qty_df, covered_area, floors):
|
| 10 |
"""
|
| 11 |
base_qty_df: DataFrame with columns: Material, Unit, Quantity_per_1000sqft
|
| 12 |
covered_area: float, in sqft
|
| 13 |
+
floors: int, total floors (including ground floor)
|
| 14 |
|
| 15 |
+
Returns a DataFrame with scaled quantities according to covered area and floors
|
| 16 |
"""
|
| 17 |
scale_factor = covered_area / 1000
|
| 18 |
+
ground_floor_qty = base_qty_df['Quantity_per_1000sqft'] * scale_factor
|
| 19 |
+
# Additional floors at 80% of ground floor quantities
|
| 20 |
+
additional_floors_qty = ground_floor_qty * 0.8 * (floors - 1) if floors > 1 else 0
|
| 21 |
+
|
| 22 |
+
base_qty_df['Scaled Quantity'] = ground_floor_qty + additional_floors_qty
|
| 23 |
return base_qty_df
|
| 24 |
|
| 25 |
def calculate_costs(qty_df, rates_df):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
df = pd.merge(qty_df, rates_df, on=['Material', 'Unit'], how='left')
|
| 27 |
df['Amount'] = df['Scaled Quantity'] * df['Rate_per_Unit']
|
| 28 |
df.fillna({'Rate_per_Unit':0, 'Amount':0}, inplace=True)
|
|
|
|
| 72 |
return buf
|
| 73 |
|
| 74 |
def main():
|
| 75 |
+
st.title("🧱 Construction Material Estimator with Floors")
|
| 76 |
|
| 77 |
+
st.markdown("Upload **Base Quantities per 1000 sqft** and **Material Rates** Excel files. Then enter project details including number of floors.")
|
| 78 |
|
| 79 |
qty_file = st.file_uploader("Upload Base Quantities Excel (Material, Unit, Quantity_per_1000sqft)", type=["xlsx", "xls"])
|
| 80 |
rate_file = st.file_uploader("Upload Material Rates Excel (Material, Unit, Rate_per_Unit)", type=["xlsx", "xls"])
|
|
|
|
| 84 |
qty_df = pd.read_excel(qty_file)
|
| 85 |
rate_df = pd.read_excel(rate_file)
|
| 86 |
|
|
|
|
| 87 |
required_qty_cols = {'Material', 'Unit', 'Quantity_per_1000sqft'}
|
| 88 |
required_rate_cols = {'Material', 'Unit', 'Rate_per_Unit'}
|
| 89 |
|
|
|
|
| 95 |
return
|
| 96 |
|
| 97 |
covered_area = st.number_input("Covered Area (sqft)", min_value=100, value=1200)
|
| 98 |
+
floors = st.number_input("Number of Floors", min_value=1, value=1)
|
| 99 |
rooms = st.number_input("Number of Rooms", min_value=0, value=3)
|
| 100 |
baths = st.number_input("Number of Bathrooms", min_value=0, value=2)
|
| 101 |
living = st.number_input("Number of Living Rooms", min_value=0, value=1)
|
| 102 |
car_porch = st.number_input("Number of Car Porches", min_value=0, value=1)
|
| 103 |
|
| 104 |
if st.button("Calculate BOQ & Cost"):
|
| 105 |
+
scaled_qty_df = calculate_scaled_quantities(qty_df, covered_area, floors)
|
| 106 |
cost_df = calculate_costs(scaled_qty_df, rate_df)
|
| 107 |
boq_table = generate_boq_table(cost_df)
|
| 108 |
|