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