Mtkhang90's picture
Update app.py
87a7c72 verified
import streamlit as st
import pandas as pd
import numpy as np
import io
import os
import replicate
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
from openai import OpenAI
st.set_page_config(page_title="Construction Estimator", layout="centered")
client = OpenAI(
api_key=os.getenv("GROQ_API_KEY"),
base_url="https://api.groq.com/openai/v1"
)
GROQ_MODEL = "llama3-8b-8192"
@st.cache_data
def load_excel(file):
return pd.read_excel(file)
@st.cache_resource
def embed_chunks(chunks):
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
embeddings = model.encode(chunks)
return embeddings, model
def query_embedding(user_query, chunks, embeddings, model):
query_vec = model.encode([user_query])
similarities = cosine_similarity(query_vec, embeddings)[0]
top_idx = np.argmax(similarities)
return chunks[top_idx]
def generate_estimate(context, user_input):
prompt = f"""You are a construction estimator in Pakistan. Using the following schedule:
{context}
Generate a BOQ with item number, description, quantity, unit, rate, and total amount for:
{user_input}
Output as a markdown table."""
response = client.chat.completions.create(
model=GROQ_MODEL,
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
def compute_total_quantities(base_df, covered_area, floors):
base_df = base_df.copy()
base_df["Adjusted Qty"] = base_df["Qty per 1000 sft"] * (covered_area / 1000)
floor_factor = 1 + max(0, floors - 1) * 0.8
base_df["Total Qty"] = base_df["Adjusted Qty"] * floor_factor
return base_df
def generate_realistic_plan(rooms, baths, living, car_porch):
prompt = f"floor plan for {rooms} rooms, {baths} bathrooms, {living} living rooms, and {car_porch} car porch in modern style"
output = replicate.run(
"cjwbw/floor-plan-generator",
input={"prompt": prompt}
)
return output
st.title("πŸ—οΈ Construction Estimator (Material + Cost + BOQ + Sketch)")
quantity_file = st.file_uploader("Upload Material Quantities Excel (per 1000 sft)", type=["xlsx"])
cost_file = st.file_uploader("Upload Material Costs Excel", type=["xlsx"])
if quantity_file and cost_file:
base_df = load_excel(quantity_file)
cost_df = load_excel(cost_file)
if "Material" in base_df.columns and "Qty per 1000 sft" in base_df.columns:
st.success("Files loaded successfully.")
rooms = st.number_input("Number of Rooms", min_value=1, value=3)
baths = st.number_input("Number of Bathrooms", min_value=1, value=2)
living = st.number_input("Number of Living Rooms", min_value=0, value=1)
car_porch = st.number_input("Number of Car Porches", min_value=0, value=1)
covered_area = st.number_input("Total Covered Area (sft)", min_value=100, value=1200)
floors = st.number_input("Number of Floors", min_value=1, value=1)
if st.button("Generate Estimate"):
computed_df = compute_total_quantities(base_df, covered_area, floors)
boq = computed_df.merge(cost_df, on="Material", how="left")
boq["Amount"] = boq["Total Qty"] * boq["Rate_per_Unit"]
st.subheader("πŸ“‹ Bill of Quantities (BOQ)")
st.dataframe(boq[["Material", "Total Qty", "Unit", "Rate_per_Unit", "Amount"]])
total_cost = boq["Amount"].sum()
st.metric("Total Estimated Cost (Rs)", f"{total_cost:,.0f}")
st.subheader("🏠 AI-Generated Floor Plan Sketch")
try:
image_url = generate_realistic_plan(rooms, baths, living, car_porch)
st.image(image_url, caption="Generated by AI (Replicate)", use_column_width=True)
except Exception as e:
st.warning("Could not generate sketch. Please check Replicate API setup.")
st.text(str(e))
else:
st.error("Quantity sheet must contain 'Material' and 'Qty per 1000 sft' columns.")
else:
st.info("Please upload both the quantity and cost Excel sheets.")