File size: 4,134 Bytes
ad932b3
 
8470341
963979a
bc0c17f
 
 
 
 
8470341
3cfdc07
 
bc0c17f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87a7c72
bc0c17f
 
87a7c72
bc0c17f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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.")