PrashanthB461 commited on
Commit
376968c
·
verified ·
1 Parent(s): 3b216cd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -229
app.py CHANGED
@@ -1,243 +1,127 @@
1
- import os
2
- import cv2
3
- import gradio as gr
4
- import torch
5
- import numpy as np
6
- from ultralytics import YOLO
7
- import time
8
- from reportlab.lib.pagesizes import letter
9
- from reportlab.pdfgen import canvas
10
- from reportlab.lib.utils import ImageReader
11
- from io import BytesIO
12
- import base64
13
- from PIL import Image
14
-
15
- # ==========================
16
- # Configuration
17
- # ==========================
18
- DEFAULT_MODEL_PATH = "models/yolov8_safety.pt"
19
- FALLBACK_MODEL = "yolov8n.pt"
20
- MODEL_PATH = os.getenv("SAFETY_MODEL_PATH", DEFAULT_MODEL_PATH)
21
- OUTPUT_DIR = "output"
22
- os.makedirs(OUTPUT_DIR, exist_ok=True)
23
-
24
- VIOLATION_LABELS = {
25
- 0: "no_helmet",
26
- 1: "no_harness",
27
- 2: "unsafe_posture",
28
- 3: "unsafe_zone"
29
- }
30
-
31
- # ==========================
32
- # Device Setup
33
- # ==========================
34
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
35
- print(f"✅ Using device: {device}")
36
-
37
- # ==========================
38
- # Load Model
39
- # ==========================
40
- try:
41
- selected_model = MODEL_PATH if os.path.isfile(MODEL_PATH) else FALLBACK_MODEL
42
- model = YOLO(selected_model)
43
- print(f"✅ Model loaded: {selected_model}")
44
- except Exception as e:
45
- print(f"❌ Failed to load model: {e}")
46
- raise
47
-
48
- # ==========================
49
- # Video Processing
50
- # ==========================
51
- def process_video(video_data, frame_skip=5, max_frames=100):
52
- try:
53
- print("Processing video data...")
54
- # Save uploaded video data to a temporary file
55
- video_path = os.path.join(OUTPUT_DIR, f"temp_{int(time.time())}.mp4")
56
- with open(video_path, "wb") as f:
57
- f.write(video_data)
58
- print(f"Video saved to {video_path}")
59
-
60
- video = cv2.VideoCapture(video_path)
61
- if not video.isOpened():
62
- raise ValueError("Could not open video file.")
63
-
64
- frame_count = 0
65
- violations = []
66
- snapshots = []
67
- processed_frame_count = 0
68
- start_time = time.time()
69
-
70
- while True:
71
- ret, frame = video.read()
72
- if not ret:
73
- break
74
-
75
- if frame_count % frame_skip != 0:
76
- frame_count += 1
77
- continue
78
-
79
- # Model inference
80
- results = model(frame, device=device)
81
-
82
- for result in results:
83
- for box in result.boxes:
84
- cls = int(box.cls)
85
- conf = float(box.conf)
86
- xywh = box.xywh.cpu().numpy()[0]
87
-
88
- label = VIOLATION_LABELS.get(cls, f"class_{cls}")
89
- violation = {
90
- "frame": frame_count,
91
- "violation": label,
92
- "confidence": round(conf, 2),
93
- "bounding_box": [round(x, 2) for x in xywh],
94
- "timestamp": frame_count / video.get(cv2.CAP_PROP_FPS)
95
- }
96
- violations.append(violation)
97
 
98
- # Save snapshot
99
- snapshot_path = os.path.join(OUTPUT_DIR, f"snapshot_{frame_count}_{label}.jpg")
100
- cv2.imwrite(snapshot_path, frame)
101
- snapshots.append({
102
- "violation": label,
103
- "frame": frame_count,
104
- "snapshot_url": f"https://huggingface.co/spaces/PrashanthB461/AI_Safety_Demo1/output/{os.path.basename(snapshot_path)}"
105
- })
106
 
107
- frame_count += 1
108
- processed_frame_count += 1
 
 
109
 
110
- if processed_frame_count >= max_frames:
111
- break
 
 
112
 
113
- if time.time() - start_time > 30:
114
- print("⏰ Exceeded 30 seconds of processing time.")
115
- break
 
116
 
117
- video.release()
118
- os.remove(video_path)
 
 
 
 
 
 
 
 
 
119
 
120
- score = calculate_safety_score(violations)
121
- pdf_report_path = generate_pdf_report(violations, snapshots, score)
 
 
 
122
 
123
- return {
124
- "violations": violations,
125
- "snapshots": snapshots,
126
- "score": score,
127
- "pdf_report_url": pdf_report_path
128
  }
129
 
130
- except Exception as e:
131
- print(f"❌ Error processing video: {e}")
132
- return {
133
- "violations": [],
134
- "snapshots": [],
135
- "score": 0,
136
- "pdf_report_url": "",
137
- "error": str(e)
138
  }
139
 
140
- # ==========================
141
- # Safety Score Calculation
142
- # ==========================
143
- def calculate_safety_score(violations):
144
- base_score = 100
145
- penalties = {
146
- "no_helmet": 25,
147
- "no_harness": 30,
148
- "unsafe_posture": 20,
149
- "unsafe_zone": 25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  }
151
- for v in violations:
152
- base_score -= penalties.get(v["violation"], 0)
153
- return max(base_score, 0)
154
-
155
- # ==========================
156
- # PDF Report Generation
157
- # ==========================
158
- def generate_pdf_report(violations, snapshots, score):
159
- try:
160
- pdf_path = os.path.join(OUTPUT_DIR, f"report_{int(time.time())}.pdf")
161
- c = canvas.Canvas(pdf_path, pagesize=letter)
162
- width, height = letter
163
-
164
- # Title
165
- c.setFont("Helvetica-Bold", 16)
166
- c.drawString(50, height - 50, "Worksite Safety Compliance Report")
167
-
168
- # Compliance Score
169
- c.setFont("Helvetica", 12)
170
- c.drawString(50, height - 80, f"Compliance Score: {score}%")
171
-
172
- # Violations Table
173
- y = height - 120
174
- c.setFont("Helvetica-Bold", 12)
175
- c.drawString(50, y, "Detected Violations:")
176
- y -= 20
177
-
178
- for v in violations:
179
- c.setFont("Helvetica", 10)
180
- text = f"Violation: {v['violation']}, Timestamp: {v['timestamp']:.2f}s, Confidence: {v['confidence']}"
181
- c.drawString(50, y, text)
182
- y -= 20
183
 
184
- # Add snapshot if available
185
- snapshot = next((s for s in snapshots if s["frame"] == v["frame"] and s["violation"] == v["violation"]), None)
186
- if snapshot and os.path.exists(snapshot["snapshot_url"].split('/')[-1]):
187
- img = ImageReader(snapshot["snapshot_url"].split('/')[-1])
188
- c.drawImage(img, 50, y - 100, width=200, height=150)
189
- y -= 170
190
-
191
- if y < 50:
192
- c.showPage()
193
- y = height - 50
194
-
195
- c.save()
196
- print(f"PDF generated at {pdf_path}")
197
- # Return a publicly accessible URL
198
- base_url = "https://huggingface.co/spaces/PrashanthB461/AI_Safety_Demo1"
199
- pdf_url = f"{base_url}/output/{os.path.basename(pdf_path)}"
200
- print(f"PDF URL: {pdf_url}")
201
- return pdf_url
202
- except Exception as e:
203
- print(f"❌ Error generating PDF: {e}")
204
- return ""
205
-
206
- # ==========================
207
- # Gradio Interface
208
- # ==========================
209
- def gradio_interface(video_file):
210
- try:
211
- if not video_file:
212
- return {"error": "Please upload a video file."}, "", "", []
213
-
214
- with open(video_file, "rb") as f:
215
- video_data = f.read()
216
-
217
- result = process_video(video_data)
218
- return (
219
- result["violations"],
220
- f"Safety Score: {result['score']}%",
221
- result["pdf_report_url"],
222
- result["snapshots"]
223
- )
224
- except Exception as e:
225
- print(f"❌ Error in gradio_interface: {e}")
226
- return {"error": str(e)}, "", "", []
227
-
228
- interface = gr.Interface(
229
- fn=gradio_interface,
230
- inputs=gr.Video(label="Upload Site Video"),
231
- outputs=[
232
- gr.JSON(label="Detected Safety Violations"),
233
- gr.Textbox(label="Compliance Score"),
234
- gr.Textbox(label="PDF Report URL"),
235
- gr.JSON(label="Snapshots")
236
- ],
237
- title="Worksite Safety Violation Analyzer",
238
- description="Upload short site videos to detect safety violations (e.g., no helmet, no harness, unsafe posture)."
239
- )
240
 
241
- if __name__ == "__main__":
242
- print("🚀 Launching Safety Analyzer App...")
243
- interface.launch()
 
 
 
1
+ import { LightningElement, api } from 'lwc';
2
+ import uploadVideo from '@salesforce/apex/VideoFileUpload.uploadVideoFile';
3
+ import { ShowToastEvent } from 'lightning/platformShowToastEvent';
4
+
5
+ export default class VideoUploadWithAI extends LightningElement {
6
+ @api recordId;
7
+ videoFile;
8
+ base64FileData;
9
+ fileName;
10
+ complianceScore;
11
+ violationsFound = false;
12
+ violationsList = [];
13
+ snapshots = [];
14
+ pdfReportUrl;
15
+ isLoading = false;
16
+ isDragging = false;
17
+
18
+ handleFileChange(event) {
19
+ const file = event.target.files[0];
20
+ if (file) {
21
+ this.fileName = file.name;
22
+ this.convertToBase64(file);
23
+ } else {
24
+ this.showToast('Error', 'No video file selected.', 'error');
25
+ }
26
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
+ convertToBase64(file) {
29
+ const reader = new FileReader();
30
+ reader.onloadend = () => {
31
+ this.base64FileData = reader.result.split(',')[1];
32
+ };
33
+ reader.readAsDataURL(file);
34
+ }
 
35
 
36
+ handleDragOver(event) {
37
+ event.preventDefault();
38
+ this.isDragging = true;
39
+ }
40
 
41
+ handleDragEnter(event) {
42
+ event.preventDefault();
43
+ this.isDragging = true;
44
+ }
45
 
46
+ handleDragLeave(event) {
47
+ event.preventDefault();
48
+ this.isDragging = false;
49
+ }
50
 
51
+ handleDrop(event) {
52
+ event.preventDefault();
53
+ this.isDragging = false;
54
+ const file = event.dataTransfer.files[0];
55
+ if (file && file.type.startsWith('video/')) {
56
+ this.fileName = file.name;
57
+ this.convertToBase64(file);
58
+ } else {
59
+ this.showToast('Error', 'Please drop a valid video file.', 'error');
60
+ }
61
+ }
62
 
63
+ get dropzoneClass() {
64
+ return this.isDragging
65
+ ? 'slds-box slds-box_small dropzone dragging'
66
+ : 'slds-box slds-box_small dropzone';
67
+ }
68
 
69
+ async handleSubmit() {
70
+ if (!this.base64FileData) {
71
+ this.showToast('Error', 'Please select a video file.', 'error');
72
+ return;
 
73
  }
74
 
75
+ if (!this.recordId) {
76
+ this.showToast('Error', 'No record ID provided. Please ensure this component is placed on a record page.', 'error');
77
+ return;
 
 
 
 
 
78
  }
79
 
80
+ this.isLoading = true;
81
+ try {
82
+ const result = await uploadVideo({
83
+ reportId: this.recordId,
84
+ fileData: this.base64FileData,
85
+ fileName: this.fileName
86
+ });
87
+ console.log('Apex Result:', JSON.stringify(result));
88
+
89
+ if (result.status === 'Reviewed') {
90
+ this.complianceScore = result.complianceScore ? parseFloat(result.complianceScore) : 0;
91
+ this.violationsList = result.violationsList || [];
92
+ this.violationsFound = this.violationsList.length > 0;
93
+ this.snapshots = result.snapshots || [];
94
+ this.pdfReportUrl = result.pdfReportUrl || '';
95
+ this.showToast('Success', 'Video processed successfully.', 'success');
96
+ } else {
97
+ let errorMessage = result.status || 'Unknown error occurred.';
98
+ if (errorMessage.includes('INSUFFICIENT_ACCESS') || errorMessage.includes('PERMISSION')) {
99
+ errorMessage += ' - Please contact your Salesforce admin to grant necessary permissions.';
100
+ }
101
+ this.showToast('Error', errorMessage, 'error');
102
+ }
103
+ } catch (error) {
104
+ console.error('Error in handleSubmit:', error);
105
+ let errorMessage = 'Failed to process video: ' + (error.message || 'Unknown error.');
106
+ if (error.message.includes('INSUFFICIENT_ACCESS') || error.message.includes('PERMISSION')) {
107
+ errorMessage += ' - Please contact your Salesforce admin to grant necessary permissions.';
108
+ }
109
+ this.showToast('Error', errorMessage, 'error');
110
+ } finally {
111
+ this.isLoading = false;
112
+ }
113
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
+ handleDownloadReport() {
116
+ if (this.pdfReportUrl) {
117
+ window.open(this.pdfReportUrl, '_blank');
118
+ } else {
119
+ this.showToast('Error', 'No PDF report available to download.', 'error');
120
+ }
121
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
+ showToast(title, message, variant) {
124
+ const event = new ShowToastEvent({ title, message, variant });
125
+ this.dispatchEvent(event);
126
+ }
127
+ }