Spaces:
Runtime error
Runtime error
File size: 14,912 Bytes
0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 18671bf 9470eb1 413c52b 9470eb1 413c52b 18671bf 413c52b 9470eb1 413c52b 9470eb1 18671bf 9470eb1 18671bf 9470eb1 18671bf 9470eb1 18671bf 9470eb1 18671bf 9470eb1 0c6d54e 9470eb1 41e9133 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 0787162 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 0787162 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0787162 9470eb1 0c6d54e 9470eb1 0c6d54e e2579fa 0787162 0c6d54e 9470eb1 0c6d54e 1f07689 0c6d54e 9470eb1 1f07689 9470eb1 0c6d54e 9470eb1 230afa7 0c6d54e 9470eb1 230afa7 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0c6d54e 9470eb1 0787162 c605070 9e4f33a 9470eb1 0787162 9e4f33a 0787162 9e4f33a 0787162 9470eb1 0787162 9470eb1 230afa7 c605070 230afa7 c605070 230afa7 0787162 9470eb1 230afa7 9e4f33a 230afa7 9e4f33a 230afa7 9470eb1 230afa7 9470eb1 c605070 9e4f33a 230afa7 9470eb1 c605070 230afa7 9470eb1 230afa7 0787162 9470eb1 0787162 c605070 497e47e 0787162 9e4f33a 0787162 9e4f33a 0787162 9470eb1 497e47e 0787162 9470eb1 230afa7 9470eb1 230afa7 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 0787162 9470eb1 |
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 |
import gradio as gr
from PIL import Image, ImageEnhance
import os
from dotenv import load_dotenv
from simple_salesforce import Salesforce
from datetime import datetime
import hashlib
import shutil
import base64
import pytz
import logging
# Setup logging
logging.basicConfig(
filename="construction_analyzer.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
# Load environment variables
logging.info("Loading environment variables")
load_dotenv()
SF_USERNAME = os.getenv("SF_USERNAME")
SF_PASSWORD = os.getenv("SF_PASSWORD")
SF_SECURITY_TOKEN = os.getenv("SF_SECURITY_TOKEN")
# Validate Salesforce credentials
if not all([SF_USERNAME, SF_PASSWORD, SF_SECURITY_TOKEN]):
logging.error("Missing Salesforce credentials")
raise ValueError("Missing Salesforce credentials. Set SF_USERNAME, SF_PASSWORD, and SF_SECURITY_TOKEN in environment variables.")
logging.info("Salesforce credentials validated successfully")
# Initialize Salesforce connection
try:
logging.info("Attempting Salesforce connection")
sf = Salesforce(
username=SF_USERNAME,
password=SF_PASSWORD,
security_token=SF_SECURITY_TOKEN,
domain='login'
)
logging.info("Salesforce connection established successfully")
except Exception as e:
logging.error(f"Salesforce connection failed: {str(e)}")
raise
# Milestone definitions with completed and pending tasks
milestone_data = {
"Excavation and Foundation": {
"percentage": 10,
"completed": ["Site clearing", "Excavation", "Foundation pouring"],
"pending": ["Structural framework", "Roofing", "Exterior work", "Interior work", "Final inspection"]
},
"Structural Framework": {
"percentage": 40,
"completed": ["Site clearing", "Excavation", "Foundation pouring", "Structural columns and beams"],
"pending": ["Roofing", "Exterior work", "Interior work", "Final inspection"]
},
"Roofing": {
"percentage": 70,
"completed": ["Site clearing", "Excavation", "Foundation pouring", "Structural columns and beams", "Roof installation"],
"pending": ["Exterior work", "Interior work", "Final inspection"]
},
"Exterior Work": {
"percentage": 85,
"completed": ["Site clearing", "Excavation", "Foundation pouring", "Structural columns and beams", "Roof installation", "Exterior walls", "Windows and doors"],
"pending": ["Interior work", "Final inspection"]
},
"Interior Work": {
"percentage": 95,
"completed": ["Site clearing", "Excavation", "Foundation pouring", "Structural columns and beams", "Roof installation", "Exterior walls", "Windows and doors", "Interior plumbing", "Electrical work", "Drywall and painting"],
"pending": ["Final inspection"]
},
"Final Completion": {
"percentage": 100,
"completed": ["Site clearing", "Excavation", "Foundation pouring", "Structural columns and beams", "Roof installation", "Exterior walls", "Windows and doors", "Interior plumbing", "Electrical work", "Drywall and painting", "Final inspection"],
"pending": []
}
}
# Adjust the timezone to Asia/Kolkata
local_timezone = pytz.timezone("Asia/Kolkata")
# Enhanced mock AI model simulating Grok-like analysis
def mock_ai_model(image):
logging.info("Analyzing image for construction progress")
img = image.convert("RGB")
max_size = 1024
img.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
# Enhance contrast and brightness for feature detection
enhancer = ImageEnhance.Contrast(img)
img_enhanced = enhancer.enhance(2.0)
enhancer = ImageEnhance.Brightness(img_enhanced)
img_enhanced = enhancer.enhance(1.2)
# Analyze image features
img_data = list(img_enhanced.getdata())
total_pixels = len(img_data)
brightness_avg = sum(sum(pixel) / 3 for pixel in img_data) / total_pixels
color_variation = max(max(pixel) - min(pixel) for pixel in img_data)
# Edge detection
edge_count = 0
width, height = img_enhanced.size
for x in range(width - 1):
for y in range(height - 1):
r, g, b = img_enhanced.getpixel((x, y))
r_next, g_next, b_next = img_enhanced.getpixel((x + 1, y + 1))
if abs(r - r_next) > 50 or abs(g - g_next) > 50 or abs(b - b_next) > 50:
edge_count += 1
edge_ratio = edge_count / (width * height)
# Simulate Grok-like reasoning for milestone detection
if brightness_avg > 220 and color_variation < 15 and edge_ratio < 0.05:
milestone = "Final Completion"
confidence = 0.95
elif brightness_avg > 180 and edge_ratio < 0.1:
milestone = "Interior Work"
confidence = 0.90
elif brightness_avg > 150 and edge_ratio < 0.2:
milestone = "Exterior Work"
confidence = 0.88
elif brightness_avg > 120 and edge_ratio < 0.3:
milestone = "Roofing"
confidence = 0.85
elif brightness_avg > 90 and edge_ratio < 0.4:
milestone = "Structural Framework"
confidence = 0.82
else:
milestone = "Excavation and Foundation"
confidence = 0.80
completed_tasks = milestone_data[milestone]["completed"]
pending_tasks = milestone_data[milestone]["pending"]
percentage = milestone_data[milestone]["percentage"]
logging.info(f"Image analyzed: Milestone={milestone}, Percentage={percentage}, Confidence={confidence}")
return milestone, percentage, confidence, completed_tasks, pending_tasks
# Process images and upload to Salesforce
def process_image(images, project_name, project_type):
logging.info(f"Processing {len(images)} images for project {project_name}")
try:
if not images:
logging.warning("No images uploaded")
return "<p style='color: red;'>Error: Please upload at least one image.</p>", "Pending", "", "", 0
if not project_name:
logging.warning("Project name missing")
return "<p style='color: red;'>Error: Project Name is required.</p>", "Pending", "", "", 0
results = []
image_urls = []
all_percentages = []
all_milestones = set()
all_completed_tasks = set()
all_pending_tasks = set()
dominant_milestone = None
dominant_image_url = None
max_confidence = 0
for idx, image_path in enumerate(images):
try:
img = Image.open(image_path)
milestone, percent_complete, confidence, completed_tasks, pending_tasks = mock_ai_model(img)
# Save image locally
upload_dir = "public_uploads"
os.makedirs(upload_dir, exist_ok=True)
unique_id = datetime.now().strftime("%Y%m%d%H%M%S")
image_filename = f"{unique_id}_{idx}_{os.path.basename(image_path)}"
saved_image_path = os.path.join(upload_dir, image_filename)
shutil.copy(image_path, saved_image_path)
# Upload to Salesforce
with open(saved_image_path, 'rb') as image_file:
image_data = base64.b64encode(image_file.read()).decode('utf-8')
content_version = {
'Title': image_filename,
'PathOnClient': saved_image_path,
'VersionData': image_data
}
try:
content_version_result = sf.ContentVersion.create(content_version)
content_version_id = content_version_result['id']
file_url = f"https://sathkruthatechsolutionspri8-dev-ed.develop.lightning.force.com/{content_version_id}"
image_urls.append(file_url)
logging.info(f"Image {idx+1} uploaded to Salesforce: {file_url}")
except Exception as e:
logging.error(f"Image {idx+1} upload failed: {str(e)}")
results.append(f"Image {idx+1}: Failed to upload to Salesforce - {str(e)}")
continue
if percent_complete > (all_percentages[0] if all_percentages else -1):
dominant_milestone = milestone
dominant_image_url = file_url
all_percentages.append(percent_complete)
all_milestones.add(milestone)
all_completed_tasks.update(completed_tasks)
all_pending_tasks.update(pending_tasks)
if confidence > max_confidence:
max_confidence = confidence
results.append(
f"Image {idx+1}: {milestone} - {percent_complete}% completion (Confidence: {confidence})<br>"
f"<strong>Completed:</strong> {', '.join(completed_tasks)}<br>"
f"<strong>Pending:</strong> {', '.join(pending_tasks) if pending_tasks else 'None'}"
)
except Exception as e:
logging.error(f"Image {idx+1} processing failed: {str(e)}")
results.append(f"Image {idx+1}: Error processing image - {str(e)}")
continue
if not results:
logging.warning("No images processed successfully")
return "<p style='color: red;'>Error: No images were successfully processed.</p>", "Failure", "", "", 0
total_percent_complete = round(sum(all_percentages) / len(all_percentages), 2)
all_milestones_str = ", ".join(all_milestones)
all_completed_tasks_str = ", ".join(sorted(all_completed_tasks))
all_pending_tasks_str = ", ".join(sorted(all_pending_tasks)) if all_pending_tasks else "None"
# Create Salesforce record
now = datetime.now(local_timezone)
local_time = now.strftime("%Y-%m-%dT%H:%M:%S") + now.strftime("%z")[:-2] + ":" + now.strftime("%z")[-2:]
record = {
"Name__c": project_name,
"Project_Type__c": project_type,
"Completion_Percentage__c": total_percent_complete,
"Current_Milestone__c": all_milestones_str,
"Last_Updated_On__c": local_time,
"Upload_Status__c": "Success",
"Comments__c": (
f"Project {project_name} at {total_percent_complete}% completion. "
f"Completed tasks: {all_completed_tasks_str}. "
f"Pending tasks: {all_pending_tasks_str}."
),
"Last_Updated_Image__c": dominant_image_url or ""
}
try:
sf.Construction__c.create(record)
logging.info(f"Salesforce record created for project {project_name}")
except Exception as e:
logging.error(f"Failed to create Salesforce record: {str(e)}")
return f"<p style='color: red;'>Error: Failed to update Salesforce - {str(e)}</p>", "Failure", "", "", 0
# Format output
output_html = "<div class='output'>"
output_html += "<h3>Processing Results:</h3><ul>"
for result in results:
if 'Error' in result or 'Failed' in result:
output_html += f"<li class='error'>{result}</li>"
else:
output_html += f"<li class='success'>{result}</li>"
output_html += "</ul>"
output_html += f"<h3>Project Summary:</h3>"
output_html += f"<p><strong>Project:</strong> {project_name} ({project_type})</p>"
output_html += f"<p><strong>Total Completion:</strong> {total_percent_complete}%</p>"
output_html += f"<p><strong>Milestones Detected:</strong> {all_milestones_str}</p>"
output_html += f"<p><strong>Completed Tasks:</strong> {all_completed_tasks_str}</p>"
output_html += f"<p><strong>Pending Tasks:</strong> {all_pending_tasks_str}</p>"
output_html += f"<p><strong>Max Confidence:</strong> {max_confidence}</p>"
output_html += f"<p><strong>Note:</strong> Only the image with the highest completion percentage is stored in Salesforce.</p>"
output_html += "</div>"
return output_html, "Success", "", f"Max Confidence: {max_confidence}", f"{total_percent_complete}%"
except Exception as e:
logging.error(f"Processing failed: {str(e)}")
return f"<p style='color: red;'>Error: {str(e)}</p>", "Failure", "", "", "0%"
# Gradio UI
with gr.Blocks(css="""
.gradio-container {
background-color: #f9f9f9;
font-family: 'Roboto', sans-serif;
padding: 20px;
}
.title {
color: #34495e;
font-size: 30px;
text-align: center;
font-weight: bold;
margin-bottom: 25px;
text-transform: uppercase;
}
.gradio-row {
text-align: center;
max-width: 800px;
margin: 0 auto;
}
.output {
text-align: left;
margin-top: 20px;
padding: 30px;
background-color: #ffffff;
border-radius: 15px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
.output h3 {
color: #2c3e50;
font-size: 22px;
font-weight: bold;
margin-bottom: 20px;
}
.output ul {
list-style-type: none;
padding: 0;
}
.output li {
padding: 14px;
margin-bottom: 18px;
border-radius: 10px;
font-size: 16px;
transition: background-color 0.3s ease;
}
.output li.success {
background-color: #27ae60;
color: white;
}
.output li.error {
background-color: #e74c3c;
color: white;
}
.button {
display: block;
margin: 25px auto;
background-color: #3498db;
color: white;
border: none;
padding: 15px 30px;
border-radius: 10px;
cursor: pointer;
font-size: 18px;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #2980b9;
}
.input {
text-align: center;
max-width: 800px;
margin: 0 auto;
}
""") as demo:
gr.Markdown("<h1 class='title'>Construction Progress Analyzer</h1>")
with gr.Row():
project_type_input = gr.Dropdown(label="Project Type", choices=["House", "Apartment"], value="House")
project_name_input = gr.Textbox(label="Project Name (Required)", placeholder="e.g. Project_12345")
image_input = gr.File(
file_count="multiple",
file_types=["image"],
label="Upload Construction Site Photos (JPG/PNG, ≤20MB each)"
)
submit_button = gr.Button("Process Images")
output_html = gr.HTML(label="Result")
submit_button.click(
fn=process_image,
inputs=[image_input, project_name_input, project_type_input],
outputs=[output_html]
)
logging.info("Launching Gradio interface")
demo.launch() |