sparsh007 commited on
Commit
c46e641
·
verified ·
1 Parent(s): 516d484

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +231 -0
app.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from azure.storage.blob import BlobServiceClient, BlobClient
3
+ import os
4
+ import cv2
5
+ import tempfile
6
+ from ultralytics import YOLO
7
+ import logging
8
+ from datetime import datetime
9
+
10
+ # Configure logging
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # Azure Storage Configuration
15
+ AZURE_ACCOUNT_NAME = "assentian"
16
+ AZURE_SAS_TOKEN = "sv=2024-11-04&ss=bfqt&srt=sco&sp=rwdlacupiytfx&se=2025-04-30T04:25:22Z&st=2025-04-16T20:25:22Z&spr=https&sig=HYrJBoOYc4PRe%2BoqBMl%2FmoL5Kz4ZYugbTLuEh63sbeo%3D"
17
+ CONTAINER_NAME = "logs"
18
+ VIDEO_PREFIX = ""
19
+
20
+ # Initialize YOLO Model
21
+ try:
22
+ YOLO_MODEL = YOLO("./best_yolov11.pt")
23
+ logger.info("YOLO model loaded successfully")
24
+ except Exception as e:
25
+ logger.error(f"Failed to load YOLO model: {e}")
26
+ raise
27
+
28
+ # Azure Blob Service Client
29
+ def get_blob_service_client():
30
+ return BlobServiceClient(
31
+ account_url=f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net",
32
+ credential=AZURE_SAS_TOKEN
33
+ )
34
+
35
+ def list_azure_videos():
36
+ try:
37
+ blob_service_client = get_blob_service_client()
38
+ container_client = blob_service_client.get_container_client(CONTAINER_NAME)
39
+ blobs = container_client.list_blobs(name_starts_with=VIDEO_PREFIX)
40
+ return [blob.name for blob in blobs if blob.name.lower().endswith(".mp4")]
41
+ except Exception as e:
42
+ logger.error(f"Error listing videos: {e}")
43
+ return []
44
+
45
+ def get_latest_azure_video():
46
+ try:
47
+ blob_service_client = get_blob_service_client()
48
+ container_client = blob_service_client.get_container_client(CONTAINER_NAME)
49
+ blobs = container_client.list_blobs(name_starts_with=VIDEO_PREFIX)
50
+
51
+ latest_blob = None
52
+ latest_time = None
53
+
54
+ for blob in blobs:
55
+ if blob.name.lower().endswith(".mp4"):
56
+ blob_client = container_client.get_blob_client(blob.name)
57
+ properties = blob_client.get_blob_properties()
58
+ if not latest_time or properties.last_modified > latest_time:
59
+ latest_time = properties.last_modified
60
+ latest_blob = blob.name
61
+
62
+ return latest_blob if latest_blob else None
63
+ except Exception as e:
64
+ logger.error(f"Error finding latest video: {e}")
65
+ return None
66
+
67
+ def download_azure_video(blob_name):
68
+ try:
69
+ blob_service_client = get_blob_service_client()
70
+ blob_client = blob_service_client.get_blob_client(
71
+ container=CONTAINER_NAME,
72
+ blob=blob_name
73
+ )
74
+
75
+ with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as temp_file:
76
+ download_stream = blob_client.download_blob()
77
+ temp_file.write(download_stream.readall())
78
+ return temp_file.name
79
+
80
+ except Exception as e:
81
+ logger.error(f"Download failed: {e}")
82
+ return None
83
+
84
+ def annotate_video(input_video_path):
85
+ try:
86
+ if not input_video_path or not os.path.exists(input_video_path):
87
+ logger.error("Invalid input video path")
88
+ return None
89
+
90
+ cap = cv2.VideoCapture(input_video_path)
91
+ if not cap.isOpened():
92
+ logger.error("Failed to open video file")
93
+ return None
94
+
95
+ # Video writer setup
96
+ frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
97
+ frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
98
+ fps = cap.get(cv2.CAP_PROP_FPS)
99
+
100
+ with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as temp_output:
101
+ output_path = temp_output.name
102
+
103
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
104
+ writer = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))
105
+
106
+ # Processing loop
107
+ while cap.isOpened():
108
+ ret, frame = cap.read()
109
+ if not ret:
110
+ break
111
+
112
+ # YOLO inference
113
+ results = YOLO_MODEL(frame)
114
+ class_counts = {}
115
+
116
+ for result in results:
117
+ for box in result.boxes:
118
+ cls_id = int(box.cls[0])
119
+ conf = float(box.conf[0])
120
+ if conf < 0.5:
121
+ continue
122
+
123
+ # Bounding box
124
+ x1, y1, x2, y2 = map(int, box.xyxy[0])
125
+ class_name = YOLO_MODEL.names[cls_id]
126
+ color = (0, 255, 0) # BGR format
127
+
128
+ # Draw rectangle
129
+ cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
130
+
131
+ # Text label
132
+ label = f"{class_name} {conf:.2f}"
133
+ cv2.putText(frame, label, (x1, y1 - 10),
134
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
135
+
136
+ # Update counts
137
+ class_counts[class_name] = class_counts.get(class_name, 0) + 1
138
+
139
+ # Add summary overlay
140
+ summary_text = " | ".join([f"{k}: {v}" for k, v in class_counts.items()])
141
+ cv2.putText(frame, summary_text, (10, 30),
142
+ cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
143
+
144
+ writer.write(frame)
145
+
146
+ # Cleanup
147
+ cap.release()
148
+ writer.release()
149
+ os.remove(input_video_path)
150
+
151
+ return output_path
152
+
153
+ except Exception as e:
154
+ logger.error(f"Annotation failed: {e}")
155
+ if 'cap' in locals(): cap.release()
156
+ if 'writer' in locals(): writer.release()
157
+ return None
158
+
159
+ def process_video(blob_name):
160
+ try:
161
+ local_path = download_azure_video(blob_name)
162
+ if not local_path:
163
+ return None
164
+ return annotate_video(local_path)
165
+ except Exception as e:
166
+ logger.error(f"Processing failed: {e}")
167
+ return None
168
+
169
+ # Gradio Interface
170
+ with gr.Blocks(title="PRISM Video Annotator", theme=gr.themes.Soft()) as demo:
171
+ gr.Markdown("# 🎥 PRISM Site Diary - Video Analyzer")
172
+
173
+ with gr.Row():
174
+ with gr.Column(scale=1):
175
+ gr.Markdown("## Azure Storage Controls")
176
+ refresh_btn = gr.Button("🔄 Refresh Video List", variant="secondary")
177
+ video_dropdown = gr.Dropdown(
178
+ label="Available Videos",
179
+ choices=list_azure_videos(),
180
+ interactive=True
181
+ )
182
+ latest_btn = gr.Button("⏩ Process Latest Video", variant="primary")
183
+ selected_btn = gr.Button("✅ Process Selected Video", variant="primary")
184
+
185
+ with gr.Column(scale=2):
186
+ gr.Markdown("## Annotated Output")
187
+ output_video = gr.Video(
188
+ label="Processed Video",
189
+ format="mp4",
190
+ interactive=False
191
+ )
192
+ status = gr.Textbox(label="Processing Status")
193
+
194
+ def update_ui():
195
+ new_choices = list_azure_videos()
196
+ return gr.Dropdown.update(choices=new_choices)
197
+
198
+ def handle_latest():
199
+ latest = get_latest_azure_video()
200
+ if latest:
201
+ output = process_video(latest)
202
+ return output if output else None
203
+ return None
204
+
205
+ # Event handlers
206
+ refresh_btn.click(
207
+ fn=update_ui,
208
+ outputs=video_dropdown,
209
+ queue=False
210
+ )
211
+
212
+ latest_btn.click(
213
+ fn=handle_latest,
214
+ outputs=output_video,
215
+ api_name="process_latest"
216
+ )
217
+
218
+ selected_btn.click(
219
+ fn=lambda x: process_video(x),
220
+ inputs=video_dropdown,
221
+ outputs=output_video,
222
+ api_name="process_selected"
223
+ )
224
+
225
+ if __name__ == "__main__":
226
+ demo.launch(
227
+ server_name="0.0.0.0",
228
+ server_port=7860,
229
+ show_error=True,
230
+ share=False
231
+ )