PrashanthB461 commited on
Commit
c337bf2
·
verified ·
1 Parent(s): 67959fd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +120 -61
app.py CHANGED
@@ -14,6 +14,8 @@ import base64
14
  import logging
15
  from retrying import retry
16
  import uuid
 
 
17
 
18
  # ==========================
19
  # Optimized Configuration
@@ -61,7 +63,8 @@ CONFIG = {
61
  "WORKER_TRACKING_DURATION": 3.0,
62
  "MAX_PROCESSING_TIME": 60, # 1 minute limit
63
  "FRAME_SKIP": 2, # Process every 2nd frame for speed
64
- "BATCH_SIZE": 16 # Frames per batch
 
65
  }
66
 
67
  # Setup logging
@@ -132,6 +135,36 @@ def calculate_iou(box1, box2):
132
 
133
  return intersection_area / union_area
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  def generate_violation_pdf(violations, score):
136
  try:
137
  pdf_filename = f"violations_{int(time.time())}.pdf"
@@ -193,6 +226,87 @@ def calculate_safety_score(violations):
193
  score = 100 - total_penalty
194
  return max(score, 0)
195
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  # ==========================
197
  # Fast Video Processing
198
  # ==========================
@@ -225,7 +339,6 @@ def process_video(video_data):
225
  helmet_violations = {}
226
  snapshots = []
227
  start_time = time.time()
228
- processed_frames = 0
229
  frame_skip = CONFIG["FRAME_SKIP"]
230
 
231
  # Process frames in batches
@@ -250,7 +363,6 @@ def process_video(video_data):
250
 
251
  batch_frames.append(frame)
252
  batch_indices.append(frame_idx)
253
- processed_frames += 1
254
 
255
  # Break if no more frames
256
  if not batch_frames:
@@ -356,8 +468,8 @@ def process_video(video_data):
356
 
357
  score = calculate_safety_score(violations)
358
  pdf_path, pdf_url, pdf_file = generate_violation_pdf(violations, score)
 
359
 
360
- # Generate violation table
361
  violation_table = "| Violation | Timestamp (s) | Confidence | Worker ID |\n"
362
  violation_table += "|------------------------|---------------|------------|-----------|\n"
363
  for v in sorted(violations, key=lambda x: x["timestamp"]):
@@ -365,76 +477,23 @@ def process_video(video_data):
365
  row = f"| {display_name:<22} | {v.get('timestamp', 0.0):.2f} | {v.get('confidence', 0.0):.2f} | {v.get('worker_id', 'N/A')} |\n"
366
  violation_table += row
367
 
368
- # Generate snapshots text
369
  snapshots_text = "\n".join(
370
  f"- Snapshot for {CONFIG['DISPLAY_NAMES'].get(s['violation'], 'Unknown')} at frame {s['frame']}: ![]({s['snapshot_base64']})"
371
  for s in snapshots
372
  ) if snapshots else "No snapshots captured."
373
 
374
- # Push to Salesforce
375
- try:
376
- sf = connect_to_salesforce()
377
- record_data = {
378
- "Compliance_Score__c": score,
379
- "Violations_Found__c": len(violations),
380
- "Status__c": "Completed",
381
- "Processing_Time__c": f"{processing_time:.2f}s"
382
- }
383
- record = sf.Safety_Video_Report__c.create(record_data)
384
- record_id = record["id"]
385
-
386
- if pdf_file:
387
- pdf_url = upload_pdf_to_salesforce(sf, pdf_file, record_id)
388
- except Exception as e:
389
- logger.error(f"Salesforce integration failed: {e}")
390
- record_id = "N/A (Salesforce error)"
391
-
392
  yield (
393
  violation_table,
394
  f"Safety Score: {score}%",
395
  snapshots_text,
396
- f"Salesforce Record ID: {record_id}",
397
- pdf_url or "N/A"
398
  )
399
 
400
  except Exception as e:
401
  logger.error(f"Error processing video: {e}", exc_info=True)
402
  yield f"Error processing video: {e}", "", "", "", ""
403
 
404
- # ==========================
405
- # Salesforce Integration
406
- # ==========================
407
- @retry(stop_max_attempt_number=3, wait_fixed=2000)
408
- def connect_to_salesforce():
409
- try:
410
- sf = Salesforce(**CONFIG["SF_CREDENTIALS"])
411
- logger.info("Connected to Salesforce")
412
- return sf
413
- except Exception as e:
414
- logger.error(f"Salesforce connection failed: {e}")
415
- raise
416
-
417
- def upload_pdf_to_salesforce(sf, pdf_file, report_id):
418
- try:
419
- encoded_pdf = base64.b64encode(pdf_file.getvalue()).decode('utf-8')
420
- content_version_data = {
421
- "Title": f"Safety_Violation_Report_{int(time.time())}",
422
- "PathOnClient": f"safety_violation_{int(time.time())}.pdf",
423
- "VersionData": encoded_pdf,
424
- "FirstPublishLocationId": report_id
425
- }
426
- content_version = sf.ContentVersion.create(content_version_data)
427
- result = sf.query(f"SELECT Id, ContentDocumentId FROM ContentVersion WHERE Id = '{content_version['id']}'")
428
- if not result['records']:
429
- logger.error("Failed to retrieve ContentVersion")
430
- return ""
431
- file_url = f"https://{sf.sf_instance}/sfc/servlet.shepherd/version/download/{content_version['id']}"
432
- logger.info(f"PDF uploaded to Salesforce: {file_url}")
433
- return file_url
434
- except Exception as e:
435
- logger.error(f"Error uploading PDF to Salesforce: {e}")
436
- return ""
437
-
438
  # ==========================
439
  # Gradio Interface
440
  # ==========================
@@ -462,10 +521,10 @@ interface = gr.Interface(
462
  gr.Textbox(label="Violation Details URL")
463
  ],
464
  title="Worksite Safety Violation Analyzer",
465
- description="Upload site videos to detect safety violations (No Helmet, No Harness, Unsafe Posture, Unsafe Zone, Improper Tool Use).",
466
  allow_flagging="never"
467
  )
468
 
469
  if __name__ == "__main__":
470
- logger.info("Launching Safety Analyzer App...")
471
  interface.launch()
 
14
  import logging
15
  from retrying import retry
16
  import uuid
17
+ from multiprocessing import Pool, cpu_count
18
+ from functools import partial
19
 
20
  # ==========================
21
  # Optimized Configuration
 
63
  "WORKER_TRACKING_DURATION": 3.0,
64
  "MAX_PROCESSING_TIME": 60, # 1 minute limit
65
  "FRAME_SKIP": 2, # Process every 2nd frame for speed
66
+ "BATCH_SIZE": 16, # Frames per batch
67
+ "PARALLEL_WORKERS": max(1, cpu_count() - 1) # Use all CPU cores except one
68
  }
69
 
70
  # Setup logging
 
135
 
136
  return intersection_area / union_area
137
 
138
+ def process_frame_batch(frame_batch, frame_indices, fps):
139
+ batch_results = []
140
+ results = model(frame_batch, device=device, conf=0.1, verbose=False)
141
+
142
+ for idx, (result, frame_idx) in enumerate(zip(results, frame_indices)):
143
+ current_time = frame_idx / fps
144
+ detections = []
145
+
146
+ boxes = result.boxes
147
+ for box in boxes:
148
+ cls = int(box.cls)
149
+ conf = float(box.conf)
150
+ label = CONFIG["VIOLATION_LABELS"].get(cls, None)
151
+
152
+ if label is None or conf < CONFIG["CONFIDENCE_THRESHOLDS"].get(label, 0.25):
153
+ continue
154
+
155
+ bbox = [round(x, 2) for x in box.xywh.cpu().numpy()[0]]
156
+ detections.append({
157
+ "frame": frame_idx,
158
+ "violation": label,
159
+ "confidence": round(conf, 2),
160
+ "bounding_box": bbox,
161
+ "timestamp": current_time
162
+ })
163
+
164
+ batch_results.append((frame_idx, detections))
165
+
166
+ return batch_results
167
+
168
  def generate_violation_pdf(violations, score):
169
  try:
170
  pdf_filename = f"violations_{int(time.time())}.pdf"
 
226
  score = 100 - total_penalty
227
  return max(score, 0)
228
 
229
+ # ==========================
230
+ # Salesforce Integration
231
+ # ==========================
232
+ @retry(stop_max_attempt_number=3, wait_fixed=2000)
233
+ def connect_to_salesforce():
234
+ try:
235
+ sf = Salesforce(**CONFIG["SF_CREDENTIALS"])
236
+ logger.info("Connected to Salesforce")
237
+ sf.describe()
238
+ return sf
239
+ except Exception as e:
240
+ logger.error(f"Salesforce connection failed: {e}")
241
+ raise
242
+
243
+ def upload_pdf_to_salesforce(sf, pdf_file, report_id):
244
+ try:
245
+ if not pdf_file:
246
+ logger.error("No PDF file provided for upload")
247
+ return ""
248
+ encoded_pdf = base64.b64encode(pdf_file.getvalue()).decode('utf-8')
249
+ content_version_data = {
250
+ "Title": f"Safety_Violation_Report_{int(time.time())}",
251
+ "PathOnClient": f"safety_violation_{int(time.time())}.pdf",
252
+ "VersionData": encoded_pdf,
253
+ "FirstPublishLocationId": report_id
254
+ }
255
+ content_version = sf.ContentVersion.create(content_version_data)
256
+ result = sf.query(f"SELECT Id, ContentDocumentId FROM ContentVersion WHERE Id = '{content_version['id']}'")
257
+ if not result['records']:
258
+ logger.error("Failed to retrieve ContentVersion")
259
+ return ""
260
+ file_url = f"https://{sf.sf_instance}/sfc/servlet.shepherd/version/download/{content_version['id']}"
261
+ logger.info(f"PDF uploaded to Salesforce: {file_url}")
262
+ return file_url
263
+ except Exception as e:
264
+ logger.error(f"Error uploading PDF to Salesforce: {e}")
265
+ return ""
266
+
267
+ def push_report_to_salesforce(violations, score, pdf_path, pdf_file):
268
+ try:
269
+ sf = connect_to_salesforce()
270
+ violations_text = "\n".join(
271
+ f"{CONFIG['DISPLAY_NAMES'].get(v.get('violation', 'Unknown'), 'Unknown')} at {v.get('timestamp', 0.0):.2f}s (Confidence: {v.get('confidence', 0.0):.2f})"
272
+ for v in violations
273
+ ) or "No violations detected."
274
+ pdf_url = f"{CONFIG['PUBLIC_URL_BASE']}{os.path.basename(pdf_path)}" if pdf_path else ""
275
+
276
+ record_data = {
277
+ "Compliance_Score__c": score,
278
+ "Violations_Found__c": len(violations),
279
+ "Violations_Details__c": violations_text,
280
+ "Status__c": "Pending",
281
+ "PDF_Report_URL__c": pdf_url
282
+ }
283
+ logger.info(f"Creating Salesforce record with data: {record_data}")
284
+ try:
285
+ record = sf.Safety_Video_Report__c.create(record_data)
286
+ logger.info(f"Created Safety_Video_Report__c record: {record['id']}")
287
+ except Exception as e:
288
+ logger.error(f"Failed to create Safety_Video_Report__c: {e}")
289
+ record = sf.Account.create({"Name": f"Safety_Report_{int(time.time())}"})
290
+ logger.warning(f"Fell back to Account record: {record['id']}")
291
+ record_id = record["id"]
292
+
293
+ if pdf_file:
294
+ uploaded_url = upload_pdf_to_salesforce(sf, pdf_file, record_id)
295
+ if uploaded_url:
296
+ try:
297
+ sf.Safety_Video_Report__c.update(record_id, {"PDF_Report_URL__c": uploaded_url})
298
+ logger.info(f"Updated record {record_id} with PDF URL: {uploaded_url}")
299
+ except Exception as e:
300
+ logger.error(f"Failed to update Safety_Video_Report__c: {e}")
301
+ sf.Account.update(record_id, {"Description": uploaded_url})
302
+ logger.info(f"Updated Account record {record_id} with PDF URL")
303
+ pdf_url = uploaded_url
304
+
305
+ return record_id, pdf_url
306
+ except Exception as e:
307
+ logger.error(f"Salesforce record creation failed: {e}", exc_info=True)
308
+ return None, ""
309
+
310
  # ==========================
311
  # Fast Video Processing
312
  # ==========================
 
339
  helmet_violations = {}
340
  snapshots = []
341
  start_time = time.time()
 
342
  frame_skip = CONFIG["FRAME_SKIP"]
343
 
344
  # Process frames in batches
 
363
 
364
  batch_frames.append(frame)
365
  batch_indices.append(frame_idx)
 
366
 
367
  # Break if no more frames
368
  if not batch_frames:
 
468
 
469
  score = calculate_safety_score(violations)
470
  pdf_path, pdf_url, pdf_file = generate_violation_pdf(violations, score)
471
+ report_id, final_pdf_url = push_report_to_salesforce(violations, score, pdf_path, pdf_file)
472
 
 
473
  violation_table = "| Violation | Timestamp (s) | Confidence | Worker ID |\n"
474
  violation_table += "|------------------------|---------------|------------|-----------|\n"
475
  for v in sorted(violations, key=lambda x: x["timestamp"]):
 
477
  row = f"| {display_name:<22} | {v.get('timestamp', 0.0):.2f} | {v.get('confidence', 0.0):.2f} | {v.get('worker_id', 'N/A')} |\n"
478
  violation_table += row
479
 
 
480
  snapshots_text = "\n".join(
481
  f"- Snapshot for {CONFIG['DISPLAY_NAMES'].get(s['violation'], 'Unknown')} at frame {s['frame']}: ![]({s['snapshot_base64']})"
482
  for s in snapshots
483
  ) if snapshots else "No snapshots captured."
484
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  yield (
486
  violation_table,
487
  f"Safety Score: {score}%",
488
  snapshots_text,
489
+ f"Salesforce Record ID: {report_id or 'N/A'}",
490
+ final_pdf_url or "N/A"
491
  )
492
 
493
  except Exception as e:
494
  logger.error(f"Error processing video: {e}", exc_info=True)
495
  yield f"Error processing video: {e}", "", "", "", ""
496
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
497
  # ==========================
498
  # Gradio Interface
499
  # ==========================
 
521
  gr.Textbox(label="Violation Details URL")
522
  ],
523
  title="Worksite Safety Violation Analyzer",
524
+ description="Upload site videos to detect safety violations (No Helmet, No Harness, Unsafe Posture, Unsafe Zone, Improper Tool Use). Non-violations are ignored.",
525
  allow_flagging="never"
526
  )
527
 
528
  if __name__ == "__main__":
529
+ logger.info("Launching Enhanced Safety Analyzer App...")
530
  interface.launch()