CoolFace
Apppublic

Mtkhang90/SmartConEstimator

sourceHugging Facemitupdated 1y agoView on Hugging Face
0likes
app.py159 linesDownload Raw Back to root
1import streamlit as st2import pandas as pd3import numpy as np4import torch5import openai6import os7import io8import re9from sentence_transformers import SentenceTransformer10from sklearn.metrics.pairwise import cosine_similarity11import matplotlib.pyplot as plt12 13# --- Groq API setup ---14openai.api_key = os.getenv("GROQ_API_KEY")15openai.api_base = "https://api.groq.com/openai/v1"16GROQ_MODEL = "llama3-8b-8192"17 18# --- Load Excel ---19@st.cache_data20def load_excel(file):21    xl = pd.read_excel(file, sheet_name=None)22    all_data = pd.concat(xl.values(), ignore_index=True)23    return all_data24 25# --- Chunk using regex instead of nltk ---26def chunk_data(df, max_tokens=100):27    text = "\n".join(df.astype(str).apply(lambda row: " | ".join(row), axis=1))28    # Split on period, newline, or semicolon29    sentences = re.split(r'(?<=[.;])\s+|\n+', text)30    chunks, current_chunk, current_len = [], [], 031 32    for sent in sentences:33        tokens = sent.split()34        if current_len + len(tokens) > max_tokens:35            chunks.append(" ".join(current_chunk))36            current_chunk, current_len = [], 037        current_chunk.append(sent)38        current_len += len(tokens)39 40    if current_chunk:41        chunks.append(" ".join(current_chunk))42 43    return chunks44 45# --- Embed chunks ---46@st.cache_resource47def embed_chunks(chunks):48    model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")49    embeddings = model.encode(chunks)50    return embeddings, model51 52# --- Query chunks ---53def query_embedding(user_query, chunks, embeddings, model):54    query_vec = model.encode([user_query])55    similarities = cosine_similarity(query_vec, embeddings)[0]56    top_indices = similarities.argsort()[::-1][:5]57    top_chunks = "\n\n".join([chunks[i] for i in top_indices])58    return top_chunks59 60# --- Generate Estimate from Groq ---61def generate_estimate(context, user_input):62    prompt = f"""You are a construction estimator in Pakistan. Use the following schedule of rates:63 64{context}65 66Estimate a full itemized construction BOQ for:67{user_input}68 69Include all relevant items for a complete house: excavation, foundation, RCC, masonry, plastering, flooring, doors, windows, paint, distemper, fans, lights, wiring, DBs, plumbing, sanitary fittings, water supply, cupboards, wardrobes, gate, etc.70 71Provide output in a markdown table with columns: Item No, Description, Qty, Unit, Rate, Amount in Rs.72"""73    response = openai.ChatCompletion.create(74        model=GROQ_MODEL,75        messages=[{"role": "user", "content": prompt}]76    )77    return response['choices'][0]['message']['content']78 79# --- Quantity Calculator ---80def calculate_quantities(rooms, area, baths, car_porch, living):81    return {82        "Total Area (sqft)": area,83        "No. of Rooms": rooms,84        "No. of Bathrooms": baths,85        "Living Rooms": living,86        "Car Porch Area (est.)": car_porch * 20087    }88 89# --- Floor Plan Sketch ---90def draw_floor_plan(rooms, baths, living, car_porch, area):91    total_spaces = rooms + baths + living + car_porch92    cols = int(np.ceil(np.sqrt(total_spaces)))93    rows = int(np.ceil(total_spaces / cols))94 95    fig, ax = plt.subplots(figsize=(10, 8))96    scale = np.sqrt(area) / 1097    width, height = scale, scale * 0.7598 99    labels = (["Room"] * rooms + ["Bath"] * baths +100              ["Living"] * living + ["Car Porch"] * car_porch)101 102    for i, label in enumerate(labels):103        row = i // cols104        col = i % cols105        x = col * width106        y = (rows - 1 - row) * height107        ax.add_patch(plt.Rectangle((x, y), width, height, edgecolor='black', facecolor='lightblue'))108        ax.text(x + width / 2, y + height / 2, label, ha='center', va='center', fontsize=8)109 110    ax.set_xlim(0, cols * width)111    ax.set_ylim(0, rows * height)112    ax.set_aspect('equal')113    ax.set_title(f"Tentative Floor Plan (Scale: 1 unit = {int(scale)} sqft)")114    ax.axis('off')115 116    buf = io.BytesIO()117    plt.savefig(buf, format='png')118    buf.seek(0)119    return buf120 121# --- Main App ---122def main():123    st.set_page_config(page_title="Construction Estimator", layout="centered")124    st.title("๐Ÿงฑ Construction Estimator (RAG + LLaMA 3 + Sketch)")125 126    excel_file = st.file_uploader("Upload Schedule of Rates (.xlsx or .xlsm)", type=["xlsx", "xlsm"])127    if excel_file:128        df = load_excel(excel_file)129        st.success("Excel file loaded successfully.")130        chunks = chunk_data(df)131        embeddings, model = embed_chunks(chunks)132 133        st.subheader("๐Ÿ—๏ธ Enter Project Details")134        rooms = st.number_input("Number of Rooms", min_value=1, value=3)135        area = st.number_input("Total Covered Area (sqft)", min_value=100, value=1200)136        baths = st.number_input("Number of Washrooms", min_value=1, value=2)137        living = st.number_input("Number of Living Rooms", min_value=0, value=1)138        car_porch = st.number_input("Number of Car Porches", min_value=0, value=1)139 140        if st.button("Generate Estimate"):141            quantities = calculate_quantities(rooms, area, baths, car_porch, living)142            user_query = f"Estimate cost for {rooms} rooms, {baths} bathrooms, {living} living rooms, total area {area} sqft, and {car_porch} car porch(es)."143            context = query_embedding(user_query, chunks, embeddings, model)144            response = generate_estimate(context, user_query)145 146            st.subheader("๐Ÿ“Š Input Quantities")147            st.json(quantities)148 149            st.subheader("๐Ÿ’ธ Estimated Construction Cost (BOQ Style)")150            st.markdown(response)151 152            buf = draw_floor_plan(rooms, baths, living, car_porch, area)153            st.subheader("๐Ÿ  Tentative Floor Plan Sketch")154            st.image(buf, caption="Auto-generated Line Plan", use_column_width=True)155            st.download_button("๐Ÿ“ฅ Download Sketch", buf, file_name="floor_plan.png", mime="image/png")156 157if __name__ == "__main__":158    main()159