roshnn24 commited on
Commit
4e54129
·
verified ·
1 Parent(s): 83caf4c

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +388 -0
app.py ADDED
@@ -0,0 +1,388 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ import torch
4
+ import ollama
5
+ import requests
6
+ from typing import List, Dict
7
+ from pydantic import BaseModel
8
+ import base64
9
+ from pathlib import Path
10
+ import tempfile
11
+ import json
12
+ from langchain_community.document_loaders import PyPDFLoader
13
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
14
+ from langchain.embeddings import HuggingFaceBgeEmbeddings
15
+ import numpy as np
16
+ from sklearn.metrics.pairwise import cosine_similarity
17
+ from fastapi.templating import Jinja2Templates
18
+ from fastapi.responses import HTMLResponse
19
+ from fastapi.requests import Request
20
+ import os
21
+
22
+
23
+ app = FastAPI()
24
+
25
+ # Enable CORS
26
+ app.add_middleware(
27
+ CORSMiddleware,
28
+ allow_origins=["*"],
29
+ allow_credentials=True,
30
+ allow_methods=["*"],
31
+ allow_headers=["*"],
32
+ )
33
+
34
+
35
+ class ProjectDetails(BaseModel):
36
+ construction_type: str
37
+ phase_count: int
38
+ description: str
39
+
40
+
41
+ class ResourcePhase(BaseModel):
42
+ phase_number: int
43
+ materials: Dict[str, Dict[str, float]]
44
+ timeline: str
45
+ dependencies: List[str]
46
+
47
+
48
+ class DocumentStore:
49
+ def __init__(self, embeddings_model):
50
+ self.embeddings_model = embeddings_model
51
+ self.documents = []
52
+ self.embeddings = None
53
+
54
+ def add_documents(self, documents):
55
+ self.documents = documents
56
+ texts = [doc.page_content for doc in documents]
57
+ self.embeddings = self.embeddings_model.embed_documents(texts)
58
+
59
+ def similarity_search(self, query, k=5):
60
+ query_embedding = self.embeddings_model.embed_query(query)
61
+ similarities = cosine_similarity([query_embedding], self.embeddings)[0]
62
+ top_k_indices = np.argsort(similarities)[-k:][::-1]
63
+ return [self.documents[i] for i in top_k_indices]
64
+
65
+
66
+ class IBMGraniteClient:
67
+ def __init__(self, api_key: str, project_id: str):
68
+ self.api_key = api_key
69
+ self.project_id = project_id
70
+ self.auth_token = None
71
+
72
+ def get_auth_token(self):
73
+ auth_url = "https://iam.cloud.ibm.com/identity/token"
74
+ auth_data = {
75
+ "grant_type": "urn:ibm:params:oauth:grant-type:apikey",
76
+ "apikey": self.api_key
77
+ }
78
+ auth_headers = {"Content-Type": "application/x-www-form-urlencoded"}
79
+
80
+ response = requests.post(auth_url, data=auth_data, headers=auth_headers)
81
+ self.auth_token = response.json().get("access_token")
82
+ if not self.auth_token:
83
+ raise Exception("Failed to retrieve IBM access token")
84
+
85
+ def analyze_phase(self, phase_details: str) -> str:
86
+ if not self.auth_token:
87
+ self.get_auth_token()
88
+
89
+ url = "https://us-south.ml.cloud.ibm.com/ml/v1/text/generation?version=2023-05-29"
90
+ headers = {
91
+ "Accept": "application/json",
92
+ "Content-Type": "application/json",
93
+ "Authorization": f"Bearer {self.auth_token}"
94
+ }
95
+
96
+ prompt = f"""Analyze the following construction phase and provide detailed insights
97
+ about resource optimization, potential risks, and timeline dependencies:
98
+ {phase_details}"""
99
+
100
+ body = {
101
+ "input": prompt,
102
+ "parameters": {
103
+ "decoding_method": "greedy",
104
+ "max_new_tokens": 900,
105
+ "repetition_penalty": 1
106
+ },
107
+ "model_id": "ibm/granite-3-8b-instruct",
108
+ "project_id": self.project_id
109
+ }
110
+
111
+ response = requests.post(url, headers=headers, json=body)
112
+ if response.status_code != 200:
113
+ raise Exception(f"IBM Granite API error: {response.text}")
114
+
115
+ return response.json().get("results", [{}])[0].get("generated_text", "")
116
+
117
+
118
+ class MaterialInferenceChain:
119
+ def __init__(self, doc_store, granite_client):
120
+ self.doc_store = doc_store
121
+ self.granite_client = granite_client
122
+
123
+ async def analyze_image(self, image_path: str, project_details: ProjectDetails) -> List[ResourcePhase]:
124
+ # First get basic material requirements using LLaVA
125
+ llava_response = ollama.chat(
126
+ model="llava:13b",
127
+ messages=[
128
+ {
129
+ "role": "user",
130
+ "content": f"""
131
+
132
+ You are an expert construction engineer. Based on the construction drawing image, list every single required construction material with their quantities for a {project_details.construction_type} project.
133
+
134
+ Go through every single item in this list of materials and choose which all are required to construct the above drawing plan:
135
+
136
+ 1. Concrete
137
+ Cement
138
+ Sand
139
+ Gravel (Aggregates)
140
+ Water
141
+ Reinforcement Steel (Rebars)
142
+ 2. Steel
143
+ Structural Steel (I-beams, H-beams)
144
+ Reinforcement Steel (Rebars)
145
+ Steel Plates
146
+ Steel Tubes & Pipes
147
+ 3. Wood
148
+ Softwood (Pine, Cedar)
149
+ Hardwood (Oak, Maple)
150
+ Plywood
151
+ Particle Board
152
+ Laminated Veneer Lumber (LVL)
153
+ Timber
154
+ 4. Masonry Materials
155
+ Clay Bricks
156
+ Concrete Blocks (CMU)
157
+ Stone (Granite, Limestone)
158
+ Mortar
159
+ 5. Glass
160
+ Float Glass
161
+ Tempered Glass
162
+ Laminated Glass
163
+ Insulated Glass
164
+ 6. Plastics and Polymers
165
+ Polyvinyl Chloride (PVC)
166
+ High-Density Polyethylene (HDPE)
167
+ Polystyrene (PS)
168
+ Polypropylene (PP)
169
+ Fiber Reinforced Polymer (FRP)
170
+ 7. Insulation Materials
171
+ Fiberglass
172
+ Mineral Wool
173
+ Polystyrene Foam (EPS, XPS)
174
+ Polyurethane Foam
175
+ Insulated Panels
176
+ 8. Roofing Materials
177
+ Asphalt Shingles
178
+ Metal Sheets
179
+ Clay or Concrete Tiles
180
+ Slate
181
+ Membrane Roofing (EPDM, TPO)
182
+ 9. Flooring Materials
183
+ Ceramic Tiles
184
+ Porcelain Tiles
185
+ Vinyl Flooring
186
+ Hardwood Flooring
187
+ Laminate Flooring
188
+ Carpet
189
+ Terrazzo
190
+ 10. Adhesives and Sealants
191
+ Epoxy Resins
192
+ Silicone Sealants
193
+ Acrylic Sealants
194
+ Polyurethane Sealants
195
+ 11. Paints and Coatings
196
+ Water-Based Paints
197
+ Oil-Based Paints
198
+ Anti-Corrosive Coatings
199
+ Fire-Resistant Paints
200
+ 12. Plumbing Materials
201
+ PVC Pipes
202
+ Copper Pipes
203
+ PEX Tubing
204
+ Cast Iron Pipes
205
+ Faucets, Valves, and Fittings
206
+ 13. Electrical Materials
207
+ Copper Wiring
208
+ Conduits (PVC, Metal)
209
+ Switches & Sockets
210
+ Electrical Panels
211
+ Circuit Breakers
212
+ Light Fixtures
213
+ 14. Fasteners and Connectors
214
+ Nails
215
+ Screws
216
+ Bolts
217
+ Washers
218
+ Nuts
219
+ Rivets
220
+ 15. Doors and Windows
221
+ Wooden Doors
222
+ Steel Doors
223
+ Aluminum Doors & Windows
224
+ uPVC Doors & Windows
225
+ 16. Gypsum and Plaster
226
+ Gypsum Boards (Drywall)
227
+ Plaster of Paris (POP)
228
+ Cement Plaster
229
+ Stucco
230
+ 17. Waterproofing Materials
231
+ Bituminous Waterproofing
232
+ Liquid Applied Membranes
233
+ Waterstops
234
+ Waterproofing Sheets
235
+ 18. Ceramics
236
+ Ceramic Tiles
237
+ Porcelain Tiles
238
+ Sanitary Wares (Sinks, Toilets)
239
+ 19. Metal Products
240
+ Aluminum Sheets
241
+ Stainless Steel Sheets
242
+ Cast Iron Products
243
+ 20. Specialized Materials
244
+ Geo-synthetics (Geo-textiles, Geo-membranes)
245
+ Acoustic Panels
246
+ Fireproofing Materials
247
+ Solar Panels
248
+
249
+
250
+
251
+
252
+ Provide the materials and quantities in the following format only:
253
+ material_name: quantity unit
254
+
255
+ Do not include any additional text, explanations, or headers.
256
+
257
+ Example Output:
258
+ Concrete: 1500 cubic_meters
259
+ Steel Reinforcement: 250 tons
260
+ Structural Steel: 800 tons""",
261
+ "images": [image_path]
262
+ }
263
+ ]
264
+ )
265
+
266
+ # Parse LLaVA's material suggestions
267
+ base_materials = self._parse_materials(llava_response["message"]["content"])
268
+
269
+ # Generate phases using IBM Granite
270
+ phases = []
271
+ for phase_num in range(1, project_details.phase_count + 1):
272
+ phase_prompt = f"""
273
+ Phase {phase_num} of {project_details.phase_count}
274
+ Project Type: {project_details.construction_type}
275
+ Description: {project_details.description}
276
+ Base Materials: {json.dumps(base_materials, indent=2)}
277
+ """
278
+
279
+ phase_analysis = self.granite_client.analyze_phase(phase_prompt)
280
+
281
+ # Create phase resource allocation
282
+ phase = ResourcePhase(
283
+ phase_number=phase_num,
284
+ materials=self._allocate_materials(base_materials, phase_num, project_details.phase_count),
285
+ timeline=f"Phase {phase_num} Timeline",
286
+ dependencies=self._extract_dependencies(phase_analysis)
287
+ )
288
+ phases.append(phase)
289
+
290
+ return phases
291
+
292
+ def _parse_materials(self, llava_output: str) -> Dict[str, Dict[str, float]]:
293
+ # Parse the material list from LLaVA's output
294
+ materials = {}
295
+ for line in llava_output.split('\n'):
296
+ if ':' in line:
297
+ material, quantity_info = line.split(':', 1)
298
+ quantity, unit = quantity_info.strip().split()
299
+ materials[material.strip()] = {
300
+ "quantity": float(quantity),
301
+ "unit": unit
302
+ }
303
+ return materials
304
+
305
+ def _allocate_materials(self, base_materials: Dict, phase_num: int, total_phases: int) -> Dict:
306
+ # Allocate materials across phases (simplified version)
307
+ phase_materials = {}
308
+ for material, info in base_materials.items():
309
+ phase_materials[material] = {
310
+ "quantity": info["quantity"] / total_phases,
311
+ "unit": info["unit"]
312
+ }
313
+ return phase_materials
314
+
315
+ def _extract_dependencies(self, phase_analysis: str) -> List[str]:
316
+ # Extract dependencies from phase analysis (simplified version)
317
+ return ["Previous phase completion"] if phase_analysis else []
318
+
319
+
320
+ # Initialize services
321
+ def init_services():
322
+ # Initialize embeddings
323
+ model_name = "BAAI/bge-base-en"
324
+ encode_kwargs = {'normalize_embeddings': True}
325
+ device = "mps" if torch.backends.mps.is_available() else "cpu"
326
+
327
+ embeddings_model = HuggingFaceBgeEmbeddings(
328
+ model_name=model_name,
329
+ model_kwargs={'device': device},
330
+ encode_kwargs=encode_kwargs
331
+ )
332
+
333
+ # Initialize document store
334
+ doc_store = DocumentStore(embeddings_model)
335
+
336
+ # Initialize IBM Granite client
337
+ granite_client = IBMGraniteClient(
338
+ api_key="9FV7l0Jxqe7ceL09MeH_g9bYioIQuABXsr1j1VHbKOpr",
339
+ project_id="4aa39c25-19d7-48c1-9cf6-e31b5c223a1f"
340
+ )
341
+
342
+ return doc_store, granite_client
343
+
344
+
345
+ # Initialize services
346
+ doc_store, granite_client = init_services()
347
+
348
+ # Initialize inference chain
349
+ inference_chain = MaterialInferenceChain(doc_store, granite_client)
350
+
351
+
352
+ # Initialize Jinja2 templates
353
+ templates = Jinja2Templates(directory="templates")
354
+
355
+ @app.get("/", response_class=HTMLResponse)
356
+ async def serve_frontend(request: Request):
357
+ return templates.TemplateResponse("index.html", {"request": request})
358
+
359
+ @app.post("/analyze-project/")
360
+ async def analyze_project(
361
+ project_details: ProjectDetails,
362
+ file: UploadFile = File(...),
363
+ ):
364
+ try:
365
+ # Save uploaded file temporarily
366
+ with tempfile.NamedTemporaryFile(delete=False, suffix=Path(file.filename).suffix) as temp_file:
367
+ content = await file.read()
368
+ temp_file.write(content)
369
+ temp_file.flush()
370
+
371
+ # Analyze the project
372
+ phases = await inference_chain.analyze_image(
373
+ temp_file.name,
374
+ project_details
375
+ )
376
+
377
+ return {
378
+ "project_type": project_details.construction_type,
379
+ "phases": phases
380
+ }
381
+
382
+ except Exception as e:
383
+ raise HTTPException(status_code=500, detail=str(e))
384
+
385
+ import uvicorn
386
+
387
+ if __name__ == "__main__":
388
+ uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)