Mtkhang90 commited on
Commit
80d2311
·
verified ·
1 Parent(s): 37fccac

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +143 -0
  2. requirements.txt +12 -0
app.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import torch
5
+ import openai
6
+ import os
7
+ from sentence_transformers import SentenceTransformer
8
+ from sklearn.metrics.pairwise import cosine_similarity
9
+ import matplotlib.pyplot as plt
10
+ import io
11
+
12
+ # Set up Groq API
13
+ openai.api_key = os.getenv("GROQ_API_KEY")
14
+ openai.api_base = "https://api.groq.com/openai/v1"
15
+ GROQ_MODEL = "llama3-8b-8192"
16
+
17
+ # Load Excel file
18
+ @st.cache_data
19
+ def load_excel(file):
20
+ xl = pd.read_excel(file, sheet_name=None)
21
+ all_data = pd.concat(xl.values(), ignore_index=True)
22
+ return all_data
23
+
24
+ # Chunk data
25
+ def chunk_data(df, chunk_size=5):
26
+ chunks = []
27
+ for i in range(0, len(df), chunk_size):
28
+ chunk = df.iloc[i:i+chunk_size].to_string(index=False)
29
+ chunks.append(chunk)
30
+ return chunks
31
+
32
+ # Embed chunks
33
+ @st.cache_resource
34
+ def embed_chunks(chunks):
35
+ model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
36
+ embeddings = model.encode(chunks)
37
+ return embeddings, model
38
+
39
+ # Query embedding
40
+ def query_embedding(user_query, chunks, embeddings, model):
41
+ query_vec = model.encode([user_query])
42
+ similarities = cosine_similarity(query_vec, embeddings)[0]
43
+ top_idx = np.argmax(similarities)
44
+ return chunks[top_idx]
45
+
46
+ # Generate estimate
47
+ def generate_estimate(context, user_input):
48
+ prompt = f"""You are a construction estimator working in Pakistan. Using the following schedule of rates:
49
+
50
+ {context}
51
+
52
+ Generate a detailed BOQ estimate including item numbers, full descriptions, unit rates, quantities and total amount in Rs for:
53
+ {user_input}
54
+
55
+ Present the result in a markdown table with columns: Item No, Description, Qty, Unit, Rate, Amount."""
56
+ response = openai.ChatCompletion.create(
57
+ model=GROQ_MODEL,
58
+ messages=[{"role": "user", "content": prompt}]
59
+ )
60
+ return response['choices'][0]['message']['content']
61
+
62
+ # Calculate quantities
63
+ def calculate_quantities(rooms, area, baths, car_porch, living):
64
+ return {
65
+ "Total Area (sqft)": area,
66
+ "No. of Rooms": rooms,
67
+ "No. of Bathrooms": baths,
68
+ "Living Rooms": living,
69
+ "Car Porch Area (est.)": car_porch * 200
70
+ }
71
+
72
+ # Generate scaled sketch
73
+ def draw_floor_plan(rooms, baths, living, car_porch, area):
74
+ total_spaces = rooms + baths + living + car_porch
75
+ cols = int(np.ceil(np.sqrt(total_spaces)))
76
+ rows = int(np.ceil(total_spaces / cols))
77
+
78
+ fig, ax = plt.subplots(figsize=(10, 8))
79
+
80
+ scale = np.sqrt(area) / 10 # Simple scale factor
81
+ width, height = scale, scale * 0.75
82
+
83
+ labels = (["Room"] * rooms + ["Bath"] * baths +
84
+ ["Living"] * living + ["Car Porch"] * car_porch)
85
+
86
+ for i, label in enumerate(labels):
87
+ row = i // cols
88
+ col = i % cols
89
+ x = col * width
90
+ y = (rows - 1 - row) * height
91
+ ax.add_patch(plt.Rectangle((x, y), width, height, edgecolor='black', facecolor='lightblue'))
92
+ ax.text(x + width / 2, y + height / 2, label, ha='center', va='center', fontsize=8)
93
+
94
+ ax.set_xlim(0, cols * width)
95
+ ax.set_ylim(0, rows * height)
96
+ ax.set_aspect('equal')
97
+ ax.set_title(f"Tentative Floor Plan (Scale: 1 unit = {int(scale)} sqft)")
98
+ ax.axis('off')
99
+
100
+ buf = io.BytesIO()
101
+ plt.savefig(buf, format='png')
102
+ buf.seek(0)
103
+ return buf
104
+
105
+ # Main app
106
+ def main():
107
+ st.set_page_config(page_title="Construction Estimator", layout="centered")
108
+ st.title("🧱 Construction Estimator (RAG + LLaMA 3 + Sketch)")
109
+
110
+ excel_file = st.file_uploader("Upload Schedule of Rates (.xlsx or .xlsm)", type=["xlsx", "xlsm"])
111
+ if excel_file:
112
+ df = load_excel(excel_file)
113
+ st.success("Excel file loaded successfully.")
114
+ chunks = chunk_data(df)
115
+ embeddings, model = embed_chunks(chunks)
116
+
117
+ st.subheader("🏗️ Enter Project Details")
118
+ rooms = st.number_input("Number of Rooms", min_value=1, value=3)
119
+ area = st.number_input("Total Covered Area (sqft)", min_value=100, value=1200)
120
+ baths = st.number_input("Number of Washrooms", min_value=1, value=2)
121
+ living = st.number_input("Number of Living Rooms", min_value=0, value=1)
122
+ car_porch = st.number_input("Number of Car Porches", min_value=0, value=1)
123
+
124
+ if st.button("Generate Estimate"):
125
+ quantities = calculate_quantities(rooms, area, baths, car_porch, living)
126
+ user_query = f"Estimate cost for {rooms} rooms, {baths} bathrooms, {living} living rooms, total area {area} sqft, and {car_porch} car porch(es)."
127
+ context = query_embedding(user_query, chunks, embeddings, model)
128
+ response = generate_estimate(context, user_query)
129
+
130
+ st.subheader("📊 Input Quantities")
131
+ st.json(quantities)
132
+
133
+ st.subheader("💸 Estimated Construction Cost (BOQ Style)")
134
+ st.markdown(response)
135
+
136
+ # Generate Sketch
137
+ buf = draw_floor_plan(rooms, baths, living, car_porch, area)
138
+ st.subheader("🏠 Tentative Floor Plan Sketch")
139
+ st.image(buf, caption="Auto-generated Line Plan", use_column_width=True)
140
+ st.download_button("📥 Download Sketch", buf, file_name="floor_plan.png", mime="image/png")
141
+
142
+ if __name__ == "__main__":
143
+ main()
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ streamlit
3
+ pandas
4
+ numpy
5
+ scikit-learn
6
+ sentence-transformers
7
+ openai==0.28.1
8
+ matplotlib
9
+ seaborn
10
+ Pillow
11
+ xlsxwriter
12
+ openpyxl