Mtkhang90 commited on
Commit
963979a
Β·
verified Β·
1 Parent(s): 17b4e68

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +99 -44
app.py CHANGED
@@ -1,75 +1,130 @@
1
  import streamlit as st
2
  import pandas as pd
3
  import numpy as np
4
- import io
5
- import matplotlib.pyplot as plt
6
  import os
7
- from openai import OpenAI
8
  from sentence_transformers import SentenceTransformer
9
  from sklearn.metrics.pairwise import cosine_similarity
 
 
 
10
 
11
- # --- Page config ---
12
  st.set_page_config(page_title="Construction Estimator", layout="centered")
13
 
14
- # --- Groq setup ---
15
  client = OpenAI(
16
  api_key=os.getenv("GROQ_API_KEY"),
17
  base_url="https://api.groq.com/openai/v1"
18
  )
19
  GROQ_MODEL = "llama3-8b-8192"
20
 
21
- # --- File loaders ---
22
- @st.cache_data
23
- def load_excel(file):
24
- return pd.read_excel(file)
 
 
 
 
 
 
 
 
25
 
26
- # --- BOQ Generator ---
27
- def generate_boq(quant_df, rate_df):
28
- boq = quant_df.merge(rate_df, on='Item', how='left')
29
- boq['Amount'] = boq['Quantity'] * boq['Rate']
30
- return boq[['Item', 'Description', 'Quantity', 'Unit', 'Rate', 'Amount']]
31
 
32
- # --- Sketch Generator (placeholder or Replicate integration) ---
33
- def generate_sketch_prompt(rooms, baths, living, car_porch):
34
- return f"Simple sketch showing {rooms} rooms, {baths} baths, {living} living, {car_porch} car porch"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  # -------------------- MAIN APP --------------------
37
  def main():
38
- st.title("🧱 Construction Estimator")
 
 
 
 
 
 
 
 
 
39
 
40
- st.subheader("πŸ”’ Upload Quantity Excel")
41
- quant_file = st.file_uploader("Material Quantities (Excel)", type=["xlsx"])
42
 
43
- st.subheader("πŸ’° Upload Rates Excel")
44
- rate_file = st.file_uploader("Material Rates (Excel)", type=["xlsx"])
45
 
46
- if quant_file and rate_file:
47
- quant_df = load_excel(quant_file)
48
- rate_df = load_excel(rate_file)
 
 
 
 
49
 
50
- st.success("Files loaded. Preview:")
51
- st.dataframe(quant_df)
52
- st.dataframe(rate_df)
53
 
54
- st.subheader("πŸ—οΈ Input Additional Project Info")
55
- rooms = st.number_input("Rooms", 1)
56
- baths = st.number_input("Bathrooms", 1)
57
- living = st.number_input("Living Rooms", 0)
58
- car_porch = st.number_input("Car Porches", 0)
59
 
60
- if st.button("Generate BOQ"):
61
- boq_df = generate_boq(quant_df, rate_df)
62
- st.subheader("πŸ“‹ BOQ")
63
- st.dataframe(boq_df)
64
 
65
- total = boq_df["Amount"].sum()
66
- st.markdown(f"### πŸ’Έ Total Estimate: Rs {total:,.0f}")
 
67
 
68
- # Optional: Sketch
69
- sketch_text = generate_sketch_prompt(rooms, baths, living, car_porch)
70
- st.subheader("🏠 Sketch Prompt (for Replicate):")
71
- st.text(sketch_text)
72
- st.info("Integrate Replicate API here if available.")
 
 
 
73
 
74
  if __name__ == "__main__":
75
  main()
 
1
  import streamlit as st
2
  import pandas as pd
3
  import numpy as np
 
 
4
  import os
 
5
  from sentence_transformers import SentenceTransformer
6
  from sklearn.metrics.pairwise import cosine_similarity
7
+ import matplotlib.pyplot as plt
8
+ import io
9
+ from openai import OpenAI
10
 
11
+ # Set page config FIRST
12
  st.set_page_config(page_title="Construction Estimator", layout="centered")
13
 
14
+ # Setup OpenAI/Groq client
15
  client = OpenAI(
16
  api_key=os.getenv("GROQ_API_KEY"),
17
  base_url="https://api.groq.com/openai/v1"
18
  )
19
  GROQ_MODEL = "llama3-8b-8192"
20
 
21
+ # Embed chunks - keep for similarity search if needed in future
22
+ @st.cache_resource
23
+ def embed_chunks(chunks):
24
+ model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
25
+ embeddings = model.encode(chunks)
26
+ return embeddings, model
27
+
28
+ # Generate estimate with Groq
29
+ def generate_estimate(context, user_input):
30
+ prompt = f"""You are a construction estimator working in Pakistan. Using the following schedule of rates and quantities:
31
+
32
+ {context}
33
 
34
+ Generate a detailed BOQ estimate including item numbers, full descriptions, unit rates, quantities, and total amount in Rs for:
35
+ {user_input}
 
 
 
36
 
37
+ Present the result in a markdown table with columns: Item No, Description, Qty, Unit, Rate, Amount."""
38
+
39
+ response = client.chat.completions.create(
40
+ model=GROQ_MODEL,
41
+ messages=[{"role": "user", "content": prompt}]
42
+ )
43
+ return response.choices[0].message.content
44
+
45
+ # Sketch generator
46
+ def draw_floor_plan(rooms, baths, living, car_porch, area):
47
+ total_spaces = rooms + baths + living + car_porch
48
+ cols = int(np.ceil(np.sqrt(total_spaces)))
49
+ rows = int(np.ceil(total_spaces / cols))
50
+
51
+ fig, ax = plt.subplots(figsize=(10, 8))
52
+ scale = np.sqrt(area) / 10
53
+ width, height = scale, scale * 0.75
54
+ labels = (["Room"] * rooms + ["Bath"] * baths + ["Living"] * living + ["Car Porch"] * car_porch)
55
+
56
+ for i, label in enumerate(labels):
57
+ row = i // cols
58
+ col = i % cols
59
+ x = col * width
60
+ y = (rows - 1 - row) * height
61
+ ax.add_patch(plt.Rectangle((x, y), width, height, edgecolor='black', facecolor='lightblue'))
62
+ ax.text(x + width / 2, y + height / 2, label, ha='center', va='center', fontsize=8)
63
+
64
+ ax.set_xlim(0, cols * width)
65
+ ax.set_ylim(0, rows * height)
66
+ ax.set_aspect('equal')
67
+ ax.set_title(f"Tentative Floor Plan (Scale: 1 unit = {int(scale)} sqft)")
68
+ ax.axis('off')
69
+
70
+ buf = io.BytesIO()
71
+ plt.savefig(buf, format='png')
72
+ buf.seek(0)
73
+ return buf
74
 
75
  # -------------------- MAIN APP --------------------
76
  def main():
77
+ st.title("🧱 Construction Estimator (RAG + LLaMA 3 + Sketch)")
78
+
79
+ st.subheader("Upload Material Data")
80
+
81
+ material_qty_file = st.file_uploader("Upload Material Quantities Excel", type=["xlsx", "xlsm"])
82
+ material_cost_file = st.file_uploader("Upload Material Costs Excel", type=["xlsx", "xlsm"])
83
+
84
+ if material_qty_file and material_cost_file:
85
+ qty_df = pd.read_excel(material_qty_file)
86
+ cost_df = pd.read_excel(material_cost_file)
87
 
88
+ st.write("### Material Quantities")
89
+ st.dataframe(qty_df)
90
 
91
+ st.write("### Material Costs")
92
+ st.dataframe(cost_df)
93
 
94
+ # Attempt to get covered area from quantities file if exists
95
+ area = None
96
+ if "Covered Area (sqft)" in qty_df.columns:
97
+ try:
98
+ area = float(qty_df["Covered Area (sqft)"].iloc[0])
99
+ except Exception:
100
+ area = None
101
 
102
+ context_qty = qty_df.to_string(index=False)
103
+ context_cost = cost_df.to_string(index=False)
104
+ context = f"Material Quantities:\n{context_qty}\n\nMaterial Costs:\n{context_cost}"
105
 
106
+ st.subheader("πŸ—οΈ Enter Other Project Details")
107
+ rooms = st.number_input("Number of Rooms", min_value=1, value=3)
108
+ baths = st.number_input("Number of Washrooms", min_value=1, value=2)
109
+ living = st.number_input("Number of Living Rooms", min_value=0, value=1)
110
+ car_porch = st.number_input("Number of Car Porches", min_value=0, value=1)
111
 
112
+ if st.button("Generate Estimate"):
113
+ user_query = f"Estimate cost for {rooms} rooms, {baths} bathrooms, {living} living rooms, and {car_porch} car porch(es)."
114
+ response = generate_estimate(context, user_query)
 
115
 
116
+ st.subheader("πŸ’Έ Estimated Construction Cost (BOQ Style)")
117
+ st.markdown("**This BOQ is a simplified estimate. Use it for planning, not execution.**")
118
+ st.markdown(response)
119
 
120
+ # Use area if available, else default 1200 sqft for sketch scaling
121
+ sketch_area = area if area else 1200
122
+ buf = draw_floor_plan(rooms, baths, living, car_porch, sketch_area)
123
+ st.subheader("🏠 Tentative Floor Plan Sketch")
124
+ st.image(buf, caption="Auto-generated Line Plan", use_column_width=True)
125
+ st.download_button("πŸ“₯ Download Sketch", buf, file_name="floor_plan.png", mime="image/png")
126
+ else:
127
+ st.info("Please upload both Material Quantities and Material Costs Excel files.")
128
 
129
  if __name__ == "__main__":
130
  main()