File size: 8,406 Bytes
2c5f171
 
 
 
 
 
 
 
72f857c
 
dc2367e
2c5f171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2c1d06f
2c5f171
 
 
 
 
 
 
 
a6fedfd
 
 
2c5f171
 
 
 
 
 
 
 
2c1d06f
a6fedfd
2c5f171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72f857c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a16e911
2c5f171
 
e3a7c25
a16e911
 
 
 
e3a7c25
a16e911
 
2c5f171
 
 
 
 
 
a16e911
 
72f857c
a16e911
 
2c1d06f
a16e911
 
 
 
 
 
 
2c5f171
 
a16e911
 
e7d22a5
 
2c5f171
a16e911
2c5f171
a16e911
 
2c5f171
 
 
 
 
 
a16e911
e3a7c25
a16e911
2c5f171
72f857c
a16e911
 
 
 
 
72f857c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a16e911
 
72f857c
a16e911
 
 
2c5f171
 
 
a16e911
 
2c5f171
 
 
39f18c1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2c5f171
 
 
e7d22a5
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
from PIL import Image, ImageDraw, ImageFont
import torch
from torchvision import models, transforms
from simple_salesforce import Salesforce
import base64
from io import BytesIO
import logging
from datetime import datetime
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
import gradio as gr

# Setup logging
logging.basicConfig(level=logging.INFO)

# Salesforce Credentials (replace with your own or environment variables)
SALESFORCE_USERNAME = "drone@sathkrutha.com"
SALESFORCE_PASSWORD = "Komal1303@"
SALESFORCE_SECURITY_TOKEN = "53AWRskW9EjWUsSL5LU6nFTy3"
SALESFORCE_INSTANCE_URL = "https://sathikrutha-a-dev-ed.my.salesforce.com"

# Salesforce Site or parent record ID where content will be linked
SITE_RECORD_ID = "a003000000xxxxx"  # TODO: Replace with actual Site__c record ID

# Connect to Salesforce
try:
    sf = Salesforce(
        username=SALESFORCE_USERNAME,
        password=SALESFORCE_PASSWORD,
        security_token=SALESFORCE_SECURITY_TOKEN,
        instance_url=SALESFORCE_INSTANCE_URL
    )
    logging.info("Salesforce connection established.")
except Exception as e:
    logging.error(f"Failed to connect to Salesforce: {str(e)}")
    raise Exception(f"Failed to connect to Salesforce: {str(e)}")

# Load the Faster R-CNN pretrained model
model = models.detection.fasterrcnn_resnet50_fpn(weights="FasterRCNN_ResNet50_FPN_Weights.COCO_V1")
model.eval()

# Image transformation for the model input
transform = transforms.Compose([
    transforms.ToTensor(),
])

VALID_FAULT_TYPES = ["Crack", "Rust", "Spalling", "Deformation", "Corrosion"]
VALID_SEVERITIES = ["Minor", "Moderate", "Critical"]

def get_severity(score):
    if score >= 0.9:
        return "Critical"
    elif score >= 0.7:
        return "Moderate"
    else:
        return "Minor"

def map_defect_type():
    return VALID_FAULT_TYPES[0]

def upload_image_to_salesforce(image, filename="detected_image.jpg", record_id=None):
    try:
        buffered = BytesIO()
        image.save(buffered, format="JPEG")
        img_data = base64.b64encode(buffered.getvalue()).decode("utf-8")

        content_version = sf.ContentVersion.create({
            "Title": filename,
            "PathOnClient": filename,
            "VersionData": img_data,
            "FirstPublishLocationId": record_id if record_id else SITE_RECORD_ID
        })
        logging.info(f"Image uploaded to Salesforce ContentVersion ID: {content_version['id']}")
        return content_version["id"]
    except Exception as e:
        logging.error(f"Failed to upload image to Salesforce: {str(e)}")
        raise Exception(f"Failed to upload image to Salesforce: {str(e)}")

def create_pdf_report(defect_list):
    buffer = BytesIO()
    c = canvas.Canvas(buffer, pagesize=letter)
    width, height = letter

    c.setFont("Helvetica-Bold", 14)
    c.drawString(30, height - 50, "Structural Defect Detection Report")

    c.setFont("Helvetica", 12)
    y = height - 80
    for i, defect in enumerate(defect_list, 1):
        text = f"{i}. Type: {defect['type']}, Confidence: {defect['confidence']}, Severity: {defect['severity']}"
        c.drawString(30, y, text)
        y -= 20
        if y < 50:
            c.showPage()
            c.setFont("Helvetica", 12)
            y = height - 50

    c.save()
    pdf = buffer.getvalue()
    buffer.close()
    return pdf

def upload_pdf_to_salesforce(pdf_bytes, filename="report.pdf", record_id=None):
    try:
        pdf_data = base64.b64encode(pdf_bytes).decode("utf-8")
        content_version = sf.ContentVersion.create({
            "Title": filename,
            "PathOnClient": filename,
            "VersionData": pdf_data,
            "FirstPublishLocationId": record_id if record_id else SITE_RECORD_ID
        })
        logging.info(f"PDF uploaded to Salesforce ContentVersion ID: {content_version['id']}")
        return content_version["id"]
    except Exception as e:
        logging.error(f"Failed to upload PDF to Salesforce: {str(e)}")
        raise Exception(f"Failed to upload PDF to Salesforce: {str(e)}")

def detect_defects(image):
    if image is None:
        return None, "No image provided"

    try:
        image_tensor = transform(image).unsqueeze(0)
        with torch.no_grad():
            predictions = model(image_tensor)

        result_image = image.copy()
        draw = ImageDraw.Draw(result_image)
        try:
            font = ImageFont.truetype("arial.ttf", 18)
        except:
            font = ImageFont.load_default()

        output = []
        for i in range(len(predictions[0]['boxes'])):
            score = predictions[0]['scores'][i].item()
            if score < 0.3:
                continue
            box = predictions[0]['boxes'][i].tolist()
            defect_type = map_defect_type()
            severity = get_severity(score)
            output.append({
                "type": defect_type,
                "confidence": round(score, 2),
                "severity": severity,
            })
            draw.rectangle(box, outline="red", width=3)
            text = f"{defect_type}: {severity}"
            draw.text((box[0], box[1] - 20 if box[1] > 20 else box[1],), text, fill="red", font=font)

        if output:
            # Fixed date formatting to ensure proper YYYY-MM-DD format
            current_date = datetime.now().strftime("%Y-%m-%d")
            inspection_name = f"Inspection-{current_date}-{len(output):03d}"

            try:
                inspection_record = sf.Drone_Structure_Inspection__c.create({
                    "Inspection_Date__c": current_date,
                    "Fault_Type__c": output[0]["type"],
                    "Severity__c": output[0]["severity"],
                    "Fault_Summary__c": str(output),
                    "Status__c": "New",
                    "Annotated_Image_URL__c": "",
                    "Report_PDF__c": ""
                })

                record_id = inspection_record.get("id")

                content_version_id_img = upload_image_to_salesforce(
                    result_image,
                    filename=f"detected_defect_{record_id}.jpg",
                    record_id=record_id
                )

                pdf_bytes = create_pdf_report(output)
                content_version_id_pdf = upload_pdf_to_salesforce(
                    pdf_bytes,
                    filename=f"defect_report_{record_id}.pdf",
                    record_id=record_id
                )

                update_data = {}
                if content_version_id_img:
                    update_data["Annotated_Image_URL__c"] = f"/sfc/servlet.shepherd/version/download/{content_version_id_img}"
                if content_version_id_pdf:
                    update_data["Report_PDF__c"] = f"/sfc/servlet.shepherd/version/download/{content_version_id_pdf}"

                if update_data:
                    sf.Drone_Structure_Inspection__c.update(record_id, update_data)

                output.append({"salesforce_record_id": record_id})

            except Exception as e:
                output.append({"error": f"Failed to create Salesforce record: {str(e)}"})

            return result_image, str(output)

        return result_image, "No defects detected above confidence threshold."

    except Exception as e:
        logging.error(f"Detection failed: {str(e)}")
        return None, f"Detection failed: {str(e)}"

# Use gr.Blocks for more control over the UI
with gr.Blocks() as demo:
    gr.Markdown(
        """
        # Structural Defect Detection with Salesforce Integration
        Upload drone-captured images to detect structural defects like cracks, rust, spalling, and deformations using Faster R-CNN. Detected faults are stored in Salesforce with annotated images.
        """
    )
    with gr.Row():
        image_input = gr.Image(type="pil", label="Upload Drone Image")
        image_output = gr.Image(label="Detection Result")
    output_text = gr.Textbox(label="Detected Faults with Severity")
    with gr.Row():
        clear_btn = gr.Button("Clear")
        submit_btn = gr.Button("Submit", variant="primary")

    submit_btn.click(
        fn=detect_defects,
        inputs=image_input,
        outputs=[image_output, output_text]
    )
    clear_btn.click(
        fn=lambda: (None, ""),
        inputs=None,
        outputs=[image_input, output_text]
    )

if __name__ == "__main__":
    demo.launch(share=False)