PrashanthB461 commited on
Commit
5acdd5f
·
verified ·
1 Parent(s): 4f4c858

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -24
app.py CHANGED
@@ -280,6 +280,14 @@ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
280
  logger.info(f"Using device: {device}")
281
 
282
  def load_model():
 
 
 
 
 
 
 
 
283
  try:
284
  processor = DetrImageProcessor.from_pretrained(CONFIG["MODEL_NAME"])
285
  model = DetrForObjectDetection.from_pretrained(CONFIG["MODEL_NAME"]).to(device)
@@ -289,7 +297,7 @@ def load_model():
289
  logger.info(f"Model classes: {model.config.id2label}")
290
  return processor, model
291
  except Exception as e:
292
- logger.error(f"Failed to load model: {e}")
293
  raise
294
 
295
  processor, model = load_model()
@@ -309,21 +317,21 @@ def is_unsafe_posture(box, frame_shape):
309
  height = y2 - y1
310
  width = x2 - x1
311
  aspect_ratio = height / max(width, 1)
312
- return aspect_ratio > 2.0 # Tall, narrow box suggests bending/unsafe posture
313
 
314
  def is_improper_tool_use(person_box, tool_box):
315
  """Placeholder for improper tool use. Fine-tune DETR for specific tools."""
316
  person_center = ((person_box[0] + person_box[2]) / 2, (person_box[1] + person_box[3]) / 2)
317
  tool_center = ((tool_box[0] + tool_box[2]) / 2, (tool_box[1] + tool_box[3]) / 2)
318
  dist = distance.euclidean(person_center, tool_center)
319
- return dist > 100 # Tool too far from person
320
 
321
  def is_unsafe_zone(person_box, frame_shape):
322
  """Check if person is in restricted area (e.g., top-left quadrant)."""
323
  px, py, pw, ph = person_box
324
  frame_h, frame_w = frame_shape
325
  person_center = (px + pw / 2, py + ph / 2)
326
- unsafe_zone = (0, 0, 0.5, 0.5) # Top-left quadrant
327
  return (unsafe_zone[0] * frame_w < person_center[0] < unsafe_zone[2] * frame_w and
328
  unsafe_zone[1] * frame_h < person_center[1] < unsafe_zone[3] * frame_h)
329
 
@@ -487,7 +495,7 @@ def push_report_to_salesforce(violations, score, pdf_path, pdf_file):
487
  logger.info(f"Creating Salesforce record with data: {record_data}")
488
  try:
489
  record = sf.Safety_Video_Report__c.create(record_data)
490
- logger.info(f"Created Safety_Video_Report__c record: {record['id']}")
491
  except Exception as e:
492
  logger.error(f"Failed to create Safety_Video_Report__c: {e}")
493
  record = sf.Account.create({"Name": f"Safety_Report_{int(time.time())}"})
@@ -497,12 +505,12 @@ def push_report_to_salesforce(violations, score, pdf_path, pdf_file):
497
  uploaded_url = upload_pdf_to_salesforce(sf, pdf_file, record_id)
498
  if uploaded_url:
499
  try:
500
- sf.Safety_Video_Report__c.update(record_id, {"PDF_Report_URL__c": uploaded_url})
501
  logger.info(f"Updated record {record_id} with PDF URL: {uploaded_url}")
502
  except Exception as e:
503
  logger.error(f"Failed to update Safety_Video_Report__c: {e}")
504
  sf.Account.update(record_id, {"Description": uploaded_url})
505
- logger.info(f"Updated Account record {record_id} with PDF URL")
506
  pdf_url = uploaded_url
507
  return record_id, pdf_url
508
  except Exception as e:
@@ -626,7 +634,7 @@ def process_video(video_data, temp_dir):
626
  break
627
  ret, frame = cap.read()
628
  if not ret:
629
- logger.warning(f"Failed to read frame {frame_idx}. Skipping.")
630
  break
631
  original_frame = frame.copy()
632
  frame = preprocess_frame(frame)
@@ -636,7 +644,7 @@ def process_video(video_data, temp_dir):
636
  batch_frames.append(Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)))
637
  batch_indices.append(frame_idx)
638
  batch_originals.append(original_frame)
639
- processed_frames += 1
640
 
641
  if not batch_frames:
642
  logger.info("No more frames to process.")
@@ -663,7 +671,7 @@ def process_video(video_data, temp_dir):
663
  progress = (processed_frames / total_frames) * 100
664
  elapsed_time = current_time - start_time
665
  fps_processed = processed_frames / elapsed_time if elapsed_time > 0 else 0
666
- yield f"Processing video... {progress:.1f}% complete (Frame {processed_frames}/{total_frames}, {fps_processed:.1f} FPS)", "", "", "", ""
667
  last_yield_time = current_time
668
 
669
  for i, (result, frame_idx, original_frame) in enumerate(zip(results, batch_indices, batch_originals)):
@@ -681,8 +689,8 @@ def process_video(video_data, temp_dir):
681
  bbox_xywh = [x + w/2, y + h/2, w, h]
682
 
683
  if label_name in ["no_helmet", "no_harness"] and conf >= CONFIG["CONFIDENCE_THRESHOLDS"].get(label_name, 0.25):
684
- if label_name == "no_helmet" and not validate_helmet_detection(original_frame, bbox_xywh, conf):
685
- logger.info(f"Frame {frame_idx}: Helmet false positive filtered at {conf:.2f} confidence")
686
  continue
687
  track_inputs.append({"bbox": bbox_xywh, "conf": conf, "cls": label_name})
688
  elif label_name == "person":
@@ -690,7 +698,7 @@ def process_video(video_data, temp_dir):
690
  elif label_name in ["hammer", "wrench"]: # Example tools; update with your dataset
691
  tool_boxes.append(bbox_xywh)
692
 
693
- # Handle Unsafe Posture, Unsafe Zone, Improper Tool Use
694
  for pbox in person_boxes:
695
  if is_unsafe_posture(pbox, original_frame.shape[:2]):
696
  track_inputs.append({"bbox": pbox, "conf": 0.9, "cls": "unsafe_posture"})
@@ -714,7 +722,6 @@ def process_video(video_data, temp_dir):
714
  tracker_id = obj['id']
715
  label = obj['cls']
716
  conf = obj['score']
717
- bbox = obj['bbox']
718
 
719
  if label not in CONFIG["VIOLATION_LABELS"]:
720
  continue
@@ -764,7 +771,7 @@ def process_video(video_data, temp_dir):
764
 
765
  if not violations:
766
  logger.info("No violations detected after processing")
767
- yield "No violations detected in the video.", "Safety Score: 100%", "No snapshots captured.", "N/A", "N/A"
768
  return
769
 
770
  snapshots = []
@@ -865,12 +872,13 @@ def process_video(video_data, temp_dir):
865
  f"Safety Score: {score}%",
866
  snapshots_text,
867
  f"Salesforce Record ID: {record_id}",
868
- final_pdf_url
 
869
  )
870
 
871
  except Exception as e:
872
  logger.error(f"Error processing video: {str(e)}", exc_info=True)
873
- yield f"Error processing video: {str(e)}", "", "", "", ""
874
  finally:
875
  if video_path and os.path.exists(video_path):
876
  try:
@@ -886,7 +894,7 @@ def gradio_interface(video_file):
886
  local_video_path = None
887
  try:
888
  if not video_file:
889
- return "No file uploaded.", "", "No file uploaded.", "", ""
890
 
891
  temp_dir = tempfile.mkdtemp(prefix="DETR_")
892
  logger.info(f"Created temporary directory for video processing: {temp_dir}")
@@ -896,7 +904,7 @@ def gradio_interface(video_file):
896
  logger.info(f"Read Gradio video file: {video_file}, size: {len(video_data)} bytes")
897
 
898
  if len(video_data) == 0:
899
- return "Uploaded video file is empty.", "", "", "", ""
900
 
901
  with tempfile.NamedTemporaryFile(suffix=".mp4", dir=temp_dir, delete=False) as temp_file:
902
  temp_file.write(video_data)
@@ -905,14 +913,14 @@ def gradio_interface(video_file):
905
  logger.info(f"Copied Gradio video to local temporary file: {local_video_path}")
906
 
907
  if not FFMPEG_AVAILABLE:
908
- return "FFmpeg is not available in the environment. Please install FFmpeg to process videos.", "", "", "", ""
909
 
910
- for status, score, snapshots_text, record_id, details_url in process_video(video_data, temp_dir):
911
- yield status, score, snapshots_text, record_id, details_url
912
 
913
  except Exception as e:
914
  logger.error(f"Error in Gradio interface: {e}", exc_info=True)
915
- yield f"Error: {str(e)}", "", "Error in processing.", "", ""
916
  finally:
917
  if local_video_path and os.path.exists(local_video_path):
918
  try:
@@ -936,7 +944,8 @@ interface = gr.Interface(
936
  gr.Textbox(label="Compliance Score"),
937
  gr.Markdown(label="Snapshots"),
938
  gr.Textbox(label="Salesforce Record ID"),
939
- gr.Textbox(label="Violation Details URL")
 
940
  ],
941
  title="Worksite Safety Violation Analyzer",
942
  description="Upload site videos to detect safety violations (No Helmet, No Harness, Unsafe Posture, Unsafe Zone, Improper Tool Use). Each unique violation is detected only once per worker.",
 
280
  logger.info(f"Using device: {device}")
281
 
282
  def load_model():
283
+ try:
284
+ # Check for timm dependency
285
+ import timm
286
+ logger.info("timm library is available.")
287
+ except ImportError as e:
288
+ logger.error("timm library is not installed. Install it with: pip install timm")
289
+ raise ImportError("timm is required for DetrConvEncoder. Run `pip install timm` and restart your runtime.") from e
290
+
291
  try:
292
  processor = DetrImageProcessor.from_pretrained(CONFIG["MODEL_NAME"])
293
  model = DetrForObjectDetection.from_pretrained(CONFIG["MODEL_NAME"]).to(device)
 
297
  logger.info(f"Model classes: {model.config.id2label}")
298
  return processor, model
299
  except Exception as e:
300
+ logger.error(f"Failed to load model: {str(e)}")
301
  raise
302
 
303
  processor, model = load_model()
 
317
  height = y2 - y1
318
  width = x2 - x1
319
  aspect_ratio = height / max(width, 1)
320
+ return aspect_ratio > 2.0
321
 
322
  def is_improper_tool_use(person_box, tool_box):
323
  """Placeholder for improper tool use. Fine-tune DETR for specific tools."""
324
  person_center = ((person_box[0] + person_box[2]) / 2, (person_box[1] + person_box[3]) / 2)
325
  tool_center = ((tool_box[0] + tool_box[2]) / 2, (tool_box[1] + tool_box[3]) / 2)
326
  dist = distance.euclidean(person_center, tool_center)
327
+ return dist > 100
328
 
329
  def is_unsafe_zone(person_box, frame_shape):
330
  """Check if person is in restricted area (e.g., top-left quadrant)."""
331
  px, py, pw, ph = person_box
332
  frame_h, frame_w = frame_shape
333
  person_center = (px + pw / 2, py + ph / 2)
334
+ unsafe_zone = (0, 0, 0.5, 0.5)
335
  return (unsafe_zone[0] * frame_w < person_center[0] < unsafe_zone[2] * frame_w and
336
  unsafe_zone[1] * frame_h < person_center[1] < unsafe_zone[3] * frame_h)
337
 
 
495
  logger.info(f"Creating Salesforce record with data: {record_data}")
496
  try:
497
  record = sf.Safety_Video_Report__c.create(record_data)
498
+ logger.info(f"Created record: {record['id']}")
499
  except Exception as e:
500
  logger.error(f"Failed to create Safety_Video_Report__c: {e}")
501
  record = sf.Account.create({"Name": f"Safety_Report_{int(time.time())}"})
 
505
  uploaded_url = upload_pdf_to_salesforce(sf, pdf_file, record_id)
506
  if uploaded_url:
507
  try:
508
+ sf.Safety_Video_Report__c.update(record_id, {"PDF_Report_URL": uploaded_url})
509
  logger.info(f"Updated record {record_id} with PDF URL: {uploaded_url}")
510
  except Exception as e:
511
  logger.error(f"Failed to update Safety_Video_Report__c: {e}")
512
  sf.Account.update(record_id, {"Description": uploaded_url})
513
+ logger.info(f"Updated account record {record_id} with PDF URL")
514
  pdf_url = uploaded_url
515
  return record_id, pdf_url
516
  except Exception as e:
 
634
  break
635
  ret, frame = cap.read()
636
  if not ret:
637
+ logger.warning(f"Failed to read frame {frame_idx}. Skipping...")
638
  break
639
  original_frame = frame.copy()
640
  frame = preprocess_frame(frame)
 
644
  batch_frames.append(Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)))
645
  batch_indices.append(frame_idx)
646
  batch_originals.append(original_frame)
647
+ processed_frames += frame_skip + 1
648
 
649
  if not batch_frames:
650
  logger.info("No more frames to process.")
 
671
  progress = (processed_frames / total_frames) * 100
672
  elapsed_time = current_time - start_time
673
  fps_processed = processed_frames / elapsed_time if elapsed_time > 0 else 0
674
+ yield f"Processing video... {progress:.1f}% complete (Frame {processed_frames}/{total_frames}, {fps_processed:.1f} FPS)", "", "", "", "", ""
675
  last_yield_time = current_time
676
 
677
  for i, (result, frame_idx, original_frame) in enumerate(zip(results, batch_indices, batch_originals)):
 
689
  bbox_xywh = [x + w/2, y + h/2, w, h]
690
 
691
  if label_name in ["no_helmet", "no_harness"] and conf >= CONFIG["CONFIDENCE_THRESHOLDS"].get(label_name, 0.25):
692
+ if label_name == "no_helmet" and not validate_helmet(original_frame, bbox_xywh, conf):
693
+ logger.info(f"Frame {frame_idx}: Height false positive violation filtered out at {conf:.2f} confidence")
694
  continue
695
  track_inputs.append({"bbox": bbox_xywh, "conf": conf, "cls": label_name})
696
  elif label_name == "person":
 
698
  elif label_name in ["hammer", "wrench"]: # Example tools; update with your dataset
699
  tool_boxes.append(bbox_xywh)
700
 
701
+ # Handle Unsafe violations
702
  for pbox in person_boxes:
703
  if is_unsafe_posture(pbox, original_frame.shape[:2]):
704
  track_inputs.append({"bbox": pbox, "conf": 0.9, "cls": "unsafe_posture"})
 
722
  tracker_id = obj['id']
723
  label = obj['cls']
724
  conf = obj['score']
 
725
 
726
  if label not in CONFIG["VIOLATION_LABELS"]:
727
  continue
 
771
 
772
  if not violations:
773
  logger.info("No violations detected after processing")
774
+ yield "No violations detected in the video.", "Safety Score: 100%", "No snapshots captured.", "N/A", "N/A", ""
775
  return
776
 
777
  snapshots = []
 
872
  f"Safety Score: {score}%",
873
  snapshots_text,
874
  f"Salesforce Record ID: {record_id}",
875
+ final_pdf_url,
876
+ ""
877
  )
878
 
879
  except Exception as e:
880
  logger.error(f"Error processing video: {str(e)}", exc_info=True)
881
+ yield f"Error processing video: {str(e)}", "", "", "", "", ""
882
  finally:
883
  if video_path and os.path.exists(video_path):
884
  try:
 
894
  local_video_path = None
895
  try:
896
  if not video_file:
897
+ return "No file uploaded.", "", "No file uploaded.", "", "", ""
898
 
899
  temp_dir = tempfile.mkdtemp(prefix="DETR_")
900
  logger.info(f"Created temporary directory for video processing: {temp_dir}")
 
904
  logger.info(f"Read Gradio video file: {video_file}, size: {len(video_data)} bytes")
905
 
906
  if len(video_data) == 0:
907
+ return "Uploaded video file is empty.", "", "", "", "", ""
908
 
909
  with tempfile.NamedTemporaryFile(suffix=".mp4", dir=temp_dir, delete=False) as temp_file:
910
  temp_file.write(video_data)
 
913
  logger.info(f"Copied Gradio video to local temporary file: {local_video_path}")
914
 
915
  if not FFMPEG_AVAILABLE:
916
+ return "FFmpeg is not available in the environment. Please install FFmpeg to process videos.", "", "", "", "", ""
917
 
918
+ for status, score, snapshots_text, record_id, details_url, _ in process_video(video_data, temp_dir):
919
+ yield status, score, snapshots_text, record_id, details_url, ""
920
 
921
  except Exception as e:
922
  logger.error(f"Error in Gradio interface: {e}", exc_info=True)
923
+ yield f"Error: {str(e)}", "", "Error in processing.", "", "", ""
924
  finally:
925
  if local_video_path and os.path.exists(local_video_path):
926
  try:
 
944
  gr.Textbox(label="Compliance Score"),
945
  gr.Markdown(label="Snapshots"),
946
  gr.Textbox(label="Salesforce Record ID"),
947
+ gr.Textbox(label="Violation Details URL"),
948
+ gr.Textbox(label="Error Log", visible=False)
949
  ],
950
  title="Worksite Safety Violation Analyzer",
951
  description="Upload site videos to detect safety violations (No Helmet, No Harness, Unsafe Posture, Unsafe Zone, Improper Tool Use). Each unique violation is detected only once per worker.",