import gradio as gr from PIL import Image import numpy as np import os from dotenv import load_dotenv from simple_salesforce import Salesforce from datetime import datetime import shutil import base64 import pytz # Load environment variables load_dotenv() SF_USERNAME = os.getenv("SF_USERNAME") SF_PASSWORD = os.getenv("SF_PASSWORD") SF_SECURITY_TOKEN = os.getenv("SF_SECURITY_TOKEN") if not all([SF_USERNAME, SF_PASSWORD, SF_SECURITY_TOKEN]): raise ValueError("Missing Salesforce credentials.") # Connect to Salesforce try: sf = Salesforce( username=SF_USERNAME, password=SF_PASSWORD, security_token=SF_SECURITY_TOKEN, domain='login' ) except Exception as e: print(f"Salesforce connection failed: {str(e)}") raise VALID_MILESTONES = ["Planning", "Foundation", "Walls Erected", "Completed"] local_timezone = pytz.timezone("Asia/Kolkata") # Milestone detection based on image brightness def detect_milestone_from_image(image_path): img = Image.open(image_path).convert("L") img_array = np.array(img) brightness = np.mean(img_array) if brightness < 80: return "Planning" elif 80 <= brightness < 130: return "Foundation" elif 130 <= brightness < 180: return "Walls Erected" else: return "Completed" def process_image(images, project_name): try: # Ensure images is a list and not empty if not images or len(images) == 0 or not isinstance(images, list): return "Error: Please upload at least one image to proceed.", "Pending", "", "", 0 milestones = [] for image in images: # Ensure each image is a valid file path if not isinstance(image, str) or not os.path.isfile(image): return "Error: Invalid image file.", "Failure", "", "", 0 img = Image.open(image) image_size_mb = os.path.getsize(image) / (1024 * 1024) if image_size_mb > 20: return "Error: One or more images exceed 20MB.", "Failure", "", "", 0 if not str(image).lower().endswith(('.jpg', '.jpeg', '.png')): return "Error: Only JPG/PNG images are supported.", "Failure", "", "", 0 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}_{os.path.basename(image)}" saved_image_path = os.path.join(upload_dir, image_filename) shutil.copy(image, saved_image_path) with open(saved_image_path, 'rb') as image_file: image_data = base64.b64encode(image_file.read()).decode('utf-8') try: content_version = { 'Title': image_filename, 'PathOnClient': saved_image_path, 'VersionData': image_data } 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}" except Exception as e: return f"Error: Failed to upload image to Salesforce - {str(e)}", "Failure", "", "", 0 milestone = detect_milestone_from_image(saved_image_path) milestones.append(milestone) final_milestone = max(set(milestones), key=milestones.count) if milestones else "Planning" milestone_completion_map = { "Planning": 10, "Foundation": 30, "Walls Erected": 50, "Completed": 100, } percent_complete = milestone_completion_map.get(final_milestone, 0) 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, "Current_Milestone__c": final_milestone, "Completion_Percentage__c": percent_complete, "Last_Updated_On__c": local_time, "Upload_Status__c": "Success", "Comments__c": f"{final_milestone}", "Last_Updated_Image__c": file_url } try: sf.Construction__c.create(record) except Exception as e: return f"Error: Failed to update Salesforce - {str(e)}", "Failure", "", "", 0 return f"

Milestone: {final_milestone}

", "Success", final_milestone, f"{percent_complete}%" except Exception as e: return f"Error: {str(e)}", "Failure", "", "", "0%" # Gradio UI with gallery input with gr.Blocks(css="") as demo: gr.Markdown("

Construction Progress Analyzer

") with gr.Row(): image_input = gr.Gallery( label="Upload Construction Site Photos (JPG/PNG, ≤ 20MB)", type="filepath", interactive=True, show_download_button=False, show_share_button=False ) project_name_input = gr.Textbox(label="Project Name (Required)", placeholder="e.g. Project_12345") submit_button = gr.Button("Process Image") output_html = gr.HTML(label="Result") upload_status = gr.Textbox(label="Upload Status") milestone = gr.Textbox(label="Detected Milestone") progress = gr.Textbox(label="Completion Percentage", interactive=False) submit_button.click( fn=process_image, inputs=[image_input, project_name_input], outputs=[output_html, upload_status, milestone, progress] ) demo.launch(share=True)