File size: 8,339 Bytes
f7ec189
 
 
 
 
521c424
f7ec189
 
 
9afe9d3
521c424
f7ec189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a054596
4b5d09a
f7ec189
4b5d09a
9afe9d3
 
4b5d09a
 
 
 
 
a054596
4b5d09a
 
a054596
4b5d09a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a054596
7b362b3
4b5d09a
521c424
4b5d09a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638a209
 
4b5d09a
 
 
 
 
 
 
 
 
 
 
 
 
 
d1970ee
 
6e86a94
4b5d09a
6e86a94
 
4b5d09a
6e86a94
d1970ee
 
6e86a94
4b5d09a
6e86a94
 
4b5d09a
6e86a94
d1970ee
 
6e86a94
4b5d09a
6e86a94
 
4b5d09a
6e86a94
d1970ee
 
6e86a94
4b5d09a
6e86a94
 
4b5d09a
6e86a94
d1970ee
 
 
4b5d09a
 
 
d1970ee
4b5d09a
 
9afe9d3
4b5d09a
521c424
 
4b5d09a
521c424
4b5d09a
521c424
4b5d09a
 
521c424
 
4b5d09a
521c424
 
 
89aed7b
521c424
4b5d09a
 
 
 
 
 
 
 
 
 
 
 
 
 
807468f
521c424
4b5d09a
f7ec189
4b5d09a
f92cfec
 
 
4b5d09a
f92cfec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c26aa17
f92cfec
4b5d09a
f7ec189
4b5d09a
f7ec189
 
 
4b5d09a
f7ec189
 
4b5d09a
 
f7ec189
 
 
 
4b5d09a
f7ec189
 
4b5d09a
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
import gradio as gr
from PIL import Image
import os
from dotenv import load_dotenv
from simple_salesforce import Salesforce
from datetime import datetime
import hashlib
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")

# Validate Salesforce credentials
if not all([SF_USERNAME, SF_PASSWORD, SF_SECURITY_TOKEN]):
    raise ValueError("Missing Salesforce credentials. Set SF_USERNAME, SF_PASSWORD, and SF_SECURITY_TOKEN in environment variables.")

# Initialize Salesforce connection
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
VALID_MILESTONES = ["Foundation", "Walls Erected", "Planning", "Completed"]

# Adjust the timezone to your local timezone (replace 'Asia/Kolkata' with your timezone if needed)
local_timezone = pytz.timezone("Asia/Kolkata")

# Deterministic AI prediction with fixed confidence and percent
def mock_ai_model(image):
    img = image.convert("RGB")
    max_size = 1024
    img.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)

    img_bytes = img.tobytes()
    img_hash = int(hashlib.sha256(img_bytes).hexdigest(), 16)

    milestone_index = img_hash % len(VALID_MILESTONES)
    milestone = VALID_MILESTONES[milestone_index]

    milestone_completion_map = {
        "Planning": 10,
        "Foundation": 30,
        "Walls Erected": 50,
        "Completed": 100,
    }
    completion_percent = milestone_completion_map.get(milestone, 0)

    confidence_raw = 0.85 + ((img_hash % 1000) / 1000) * (0.95 - 0.85)
    confidence_score = round(confidence_raw, 2)

    return milestone, completion_percent, confidence_score

# Image processing and Salesforce upload
def process_image(image, project_name):
    try:
        if image is None:
            return "Error: Please upload an image to proceed.", "Pending", "", "", 0

        img = Image.open(image)
        image_size_mb = os.path.getsize(image) / (1024 * 1024)
        if image_size_mb > 20:
            return "Error: Image size exceeds 20MB.", "Failure", "", "", 0
        if not str(image).lower().endswith(('.jpg', '.jpeg', '.png')): 
            return "Error: Only JPG/PNG images are supported.", "Failure", "", "", 0

        # Save image to public folder temporarily before uploading to Salesforce
        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)

        # Convert image to base64 before uploading to Salesforce
        with open(saved_image_path, 'rb') as image_file:
            image_data = base64.b64encode(image_file.read()).decode('utf-8')

        # Create the ContentVersion record in Salesforce
        content_version = {
            'Title': image_filename,
            'PathOnClient': saved_image_path,
            'VersionData': image_data
        }

        # Upload the file to Salesforce
        try:
            content_version_result = sf.ContentVersion.create(content_version)
            content_version_id = content_version_result['id']

            # Generate the public URL for the uploaded file in Salesforce
            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

        # AI-based milestone and completion prediction
        milestone, percent_complete, confidence_score = mock_ai_model(img)

        # Detailed Completion Breakdown (based on detected milestone)
        completion_details = {
            "Planning": {
                "completed": [
                    "Project outline and goals set, initial designs done."
                ],
                "not_completed": [
                    "Detailed plans, permits, and contractor hiring pending."
                ]
            },
            "Foundation": {
                "completed": [
                    "Foundation work is complete, concrete is poured."
                ],
                "not_completed": [
                    "Plumbing, electrical groundwork not yet done."
                ]
            },
            "Walls Erected": {
                "completed": [
                    "All structural walls are up."
                ],
                "not_completed": [
                    "Roofing, windows, and internal walls are not yet finished."
                ]
            },
            "Completed": {
                "completed": [
                    "All phases of the project are finished, including final touches."
                ],
                "not_completed": [
                    "There should be no more pending work."
                ]
            }
        }

        # Get the detailed completion information based on the detected milestone
        completed_work = "\n".join([f"{idx+1}. {task}" for idx, task in enumerate(completion_details[milestone]["completed"])])
        not_completed_work = "\n".join([f"{idx+1}. {task}" for idx, task in enumerate(completion_details[milestone]["not_completed"])])

        # Adjust the current time to local timezone
        local_time = datetime.now(local_timezone).strftime("%Y-%m-%dT%H:%M:%S%z")  # Corrected ISO 8601 format with timezone

        # Create the Salesforce record with the image URL and AI prediction
        record = {
            "Name__c": project_name,
            "Current_Milestone__c": milestone,
            "Completion_Percentage__c": percent_complete,
            "Last_Updated_On__c": local_time,  # Corrected format for Salesforce
            "Upload_Status__c": "Success",
            "Comments__c": f"{milestone} with {confidence_score*100}% confidence",  # Removed "AI Prediction:"
            "Last_Updated_Image__c": file_url
        }

        # Upload the record to Salesforce
        try:
            sf.Construction__c.create(record)
        except Exception as e:
            return f"Error: Failed to update Salesforce - {str(e)}", "Failure", "", "", 0

        # Return the detailed result in the desired format
        result = f"""
        Completed:
        
        {completed_work}

        Not Completed:

        {not_completed_work}

        Confidence Score: {confidence_score * 100}%
        """

        return result, "Success", milestone, f"Confidence Score: {confidence_score}", percent_complete

    except Exception as e:
        return f"Error: {str(e)}", "Failure", "", "", 0

# Gradio UI with added styling
with gr.Blocks(css="""
    .gradio-container {
        background-color: #f0f4f8;
        font-family: Arial;
    }
    .title {
        color: #2c3e50;
        font-size: 24px;
        text-align: center;
        font-weight: bold;
    }
    .gradio-row {
        text-align: center;
    }
    .gradio-container .output {
        text-align: center;
    }
    .gradio-container .input {
        text-align: center;
    }
    .gradio-container .button {
        display: block;
        margin: 0 auto;
    }
""") as demo:
    gr.Markdown("<h1 class='title'></h1>")
    with gr.Row():
        image_input = gr.Image(type="filepath", label="Upload Construction Site Photo (JPG/PNG, ≤ 20MB)")
        project_name_input = gr.Textbox(label="Project Name (Required)", placeholder="e.g. Project_12345")

    submit_button = gr.Button("Process Image")
    output_text = gr.Textbox(label="Result")
    upload_status = gr.Textbox(label="Upload Status")
    milestone = gr.Textbox(label="Detected Milestone")
    confidence = gr.Textbox(label="Confidence Score")
    progress = gr.Slider(0, 100, label="Completion Percentage", interactive=False, value=0)

    submit_button.click(
        fn=process_image,
        inputs=[image_input, project_name_input],
        outputs=[output_text, upload_status, milestone, confidence, progress]
    )

demo.launch(share=True)