webapp1 commited on
Commit
40fccd9
·
verified ·
1 Parent(s): 5a8d928

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -34
app.py CHANGED
@@ -86,7 +86,6 @@ except:
86
  # --- Helper Functions ---
87
 
88
  def get_geo_info(ip_or_url=None):
89
- """Fetches location and weather based on IP or URL."""
90
  try:
91
  target = ""
92
  if ip_or_url:
@@ -125,11 +124,8 @@ def process_accident_async(stream_id, frame, location, confidence, severity):
125
  msg['From'] = ALERT_EMAIL_SENDER
126
  msg['To'] = ALERT_EMAIL_RECEIVER
127
  msg.set_content(f"Incident Report\nLocation: {location}\nSeverity: {severity}\nConfidence: {confidence}%\nTime: {datetime.datetime.now()}\n\nSystem has locked this stream for investigation.")
128
-
129
- # Attach Snapshot
130
  msg.add_attachment(buffer.tobytes(), maintype='image', subtype='jpeg', filename='incident.jpg')
131
 
132
- # 🚨 Attach Original Video if it's an uploaded file and under 20MB 🚨
133
  source = app.config.get(f'SRC_{stream_id}')
134
  is_file = source and not str(source).startswith('http') and os.path.exists(source)
135
  if is_file:
@@ -137,16 +133,13 @@ def process_accident_async(stream_id, frame, location, confidence, severity):
137
  if os.path.getsize(source) < 20 * 1024 * 1024:
138
  with open(source, 'rb') as f:
139
  msg.add_attachment(f.read(), maintype='video', subtype='mp4', filename='incident_video.mp4')
140
- except Exception as ve:
141
- print(f"Failed to attach video: {ve}")
142
 
143
  context = ssl.create_default_context()
144
  with smtplib.SMTP_SSL('smtp.gmail.com', 465, context=context) as smtp:
145
  smtp.login(ALERT_EMAIL_SENDER, ALERT_EMAIL_PASSWORD)
146
  smtp.send_message(msg)
147
- print(f"📧 Dispatch Email Sent for Stream {stream_id}", flush=True)
148
- except Exception as e:
149
- print(f"📧 Email Failed: {e}", flush=True)
150
 
151
  def run_temporal_analysis(stream_id, frames_3d_copy, prob_max, prob_mean, prob_min, yolo_max_conf, raw_frame, location):
152
  state = active_streams.get(stream_id)
@@ -164,7 +157,6 @@ def run_temporal_analysis(stream_id, frames_3d_copy, prob_max, prob_mean, prob_m
164
  confidence = float(ensemble_probs[final_idx] * 100)
165
  severity = classes[final_idx]
166
 
167
- # Lock the decision if confidence is high
168
  if confidence > 85:
169
  state["final_decision"] = True
170
  state["label"] = f"Incident Logged: {severity.capitalize()}"
@@ -180,8 +172,7 @@ def run_temporal_analysis(stream_id, frames_3d_copy, prob_max, prob_mean, prob_m
180
  state["cnn"] = round(yolo_max_conf, 1)
181
  state["rcnn"] = round(float(np.max(prob_3d)) * 100, 1)
182
 
183
- except Exception as e:
184
- print(f"AI Error: {e}")
185
  finally:
186
  if state: state["is_analyzing"] = False
187
 
@@ -193,11 +184,13 @@ def init_upload():
193
  filename = secure_filename(file.filename)
194
  path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
195
  file.save(path)
196
- # Strict Nil for Local Files
197
  loc, wx, file_time = "Nil", "--", "--"
198
  stream_id = f"up_{uuid.uuid4().hex}"
199
  app.config[f'SRC_{stream_id}'] = path
200
- active_streams[stream_id] = {"label": "Initializing...", "final_decision": False, "confidence": 0, "severity": "--", "plates": [], "show_tracking": True}
 
 
 
201
  return jsonify({"stream_id": stream_id, "location": loc, "weather": wx, "time": file_time})
202
 
203
  @app.route('/init_stream', methods=['POST'])
@@ -207,43 +200,90 @@ def init_stream():
207
  v_time = datetime.datetime.now().strftime("%H:%M:%S")
208
  stream_id = f"live_{uuid.uuid4().hex}"
209
  app.config[f'SRC_{stream_id}'] = url
210
- active_streams[stream_id] = {"label": "Connecting...", "final_decision": False, "confidence": 0, "severity": "--", "plates": [], "show_tracking": True}
 
 
 
211
  return jsonify({"stream_id": stream_id, "location": loc, "weather": wx, "time": v_time})
212
 
213
- @app.route('/toggle_tracking/<stream_id>', methods=['POST'])
214
- def toggle_tracking(stream_id):
215
- """Dynamic flip between AI Tracking and Raw Feed without restarting the stream"""
216
- if stream_id in active_streams:
217
- active_streams[stream_id]["show_tracking"] = request.json.get("track", True)
218
- return jsonify({"status": "ok"})
219
- return jsonify({"error": "not found"}), 404
 
 
 
 
 
 
220
 
221
  def video_stream_gen(stream_id, source, location):
222
  cap = cv2.VideoCapture(source)
 
 
 
 
 
223
  frames_3d = []
224
  yolo_probs = []
225
  frame_count = 0
 
226
 
227
  while True:
228
- ret, frame = cap.read()
229
- if not ret: break
230
-
231
  state = active_streams.get(stream_id)
232
  if not state: break
233
 
234
- # 1. Visualization Toggle
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  if state.get("show_tracking", True):
236
  track_res = model_tracker(frame, classes=[2, 3, 5, 7], verbose=False, conf=0.3)[0]
237
  display_frame = track_res.plot()
238
  else:
239
  display_frame = frame
240
 
241
- # 2. Severity Scanning (Only runs if a final decision hasn't been made yet)
242
  if not state.get("final_decision"):
243
  res = model_yolo(frame, verbose=False)[0]
 
 
244
  if res.probs is not None:
245
- yolo_probs.append(res.probs.data.cpu().numpy())
246
- if len(yolo_probs) > 10: yolo_probs.pop(0)
 
 
 
 
 
 
 
 
247
 
248
  f_3d = cv2.resize(frame, (112, 112))
249
  frames_3d.append(cv2.cvtColor(f_3d, cv2.COLOR_BGR2RGB))
@@ -260,8 +300,16 @@ def video_stream_gen(stream_id, source, location):
260
  )).start()
261
 
262
  _, buffer = cv2.imencode('.jpg', display_frame)
263
- yield (b'--frame\r\nContent-Type: image/jpeg\r\n\r\n' + buffer.tobytes() + b'\r\n')
 
264
  frame_count += 1
 
 
 
 
 
 
 
265
 
266
  cap.release()
267
 
@@ -284,14 +332,12 @@ def predict_traffic_risk():
284
 
285
  prob = float(model_traffic.predict_proba(df)[0][1] * 100)
286
 
 
287
  if prob >= 70: status = "Major"
288
  elif prob >= 35: status = "Moderate"
289
  else: status = "Minor"
290
 
291
- # No longer returning the exact percentage number to frontend
292
- return jsonify({
293
- "status": status
294
- })
295
  except Exception as e: return jsonify({"error": str(e)}), 500
296
 
297
  @app.route('/')
 
86
  # --- Helper Functions ---
87
 
88
  def get_geo_info(ip_or_url=None):
 
89
  try:
90
  target = ""
91
  if ip_or_url:
 
124
  msg['From'] = ALERT_EMAIL_SENDER
125
  msg['To'] = ALERT_EMAIL_RECEIVER
126
  msg.set_content(f"Incident Report\nLocation: {location}\nSeverity: {severity}\nConfidence: {confidence}%\nTime: {datetime.datetime.now()}\n\nSystem has locked this stream for investigation.")
 
 
127
  msg.add_attachment(buffer.tobytes(), maintype='image', subtype='jpeg', filename='incident.jpg')
128
 
 
129
  source = app.config.get(f'SRC_{stream_id}')
130
  is_file = source and not str(source).startswith('http') and os.path.exists(source)
131
  if is_file:
 
133
  if os.path.getsize(source) < 20 * 1024 * 1024:
134
  with open(source, 'rb') as f:
135
  msg.add_attachment(f.read(), maintype='video', subtype='mp4', filename='incident_video.mp4')
136
+ except Exception as ve: pass
 
137
 
138
  context = ssl.create_default_context()
139
  with smtplib.SMTP_SSL('smtp.gmail.com', 465, context=context) as smtp:
140
  smtp.login(ALERT_EMAIL_SENDER, ALERT_EMAIL_PASSWORD)
141
  smtp.send_message(msg)
142
+ except Exception as e: pass
 
 
143
 
144
  def run_temporal_analysis(stream_id, frames_3d_copy, prob_max, prob_mean, prob_min, yolo_max_conf, raw_frame, location):
145
  state = active_streams.get(stream_id)
 
157
  confidence = float(ensemble_probs[final_idx] * 100)
158
  severity = classes[final_idx]
159
 
 
160
  if confidence > 85:
161
  state["final_decision"] = True
162
  state["label"] = f"Incident Logged: {severity.capitalize()}"
 
172
  state["cnn"] = round(yolo_max_conf, 1)
173
  state["rcnn"] = round(float(np.max(prob_3d)) * 100, 1)
174
 
175
+ except Exception as e: pass
 
176
  finally:
177
  if state: state["is_analyzing"] = False
178
 
 
184
  filename = secure_filename(file.filename)
185
  path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
186
  file.save(path)
 
187
  loc, wx, file_time = "Nil", "--", "--"
188
  stream_id = f"up_{uuid.uuid4().hex}"
189
  app.config[f'SRC_{stream_id}'] = path
190
+ active_streams[stream_id] = {
191
+ "label": "Initializing...", "final_decision": False, "confidence": 0, "severity": "--",
192
+ "plates": [], "show_tracking": True, "paused": False, "seek_to": None, "progress": 0
193
+ }
194
  return jsonify({"stream_id": stream_id, "location": loc, "weather": wx, "time": file_time})
195
 
196
  @app.route('/init_stream', methods=['POST'])
 
200
  v_time = datetime.datetime.now().strftime("%H:%M:%S")
201
  stream_id = f"live_{uuid.uuid4().hex}"
202
  app.config[f'SRC_{stream_id}'] = url
203
+ active_streams[stream_id] = {
204
+ "label": "Connecting...", "final_decision": False, "confidence": 0, "severity": "--",
205
+ "plates": [], "show_tracking": True, "paused": False, "seek_to": None, "progress": 0
206
+ }
207
  return jsonify({"stream_id": stream_id, "location": loc, "weather": wx, "time": v_time})
208
 
209
+ @app.route('/video_control/<stream_id>', methods=['POST'])
210
+ def video_control(stream_id):
211
+ """Dynamic Video Controls for the AI Player"""
212
+ state = active_streams.get(stream_id)
213
+ if not state: return jsonify({"error": "not found"}), 404
214
+
215
+ action = request.json.get('action')
216
+ if action == 'toggle_tracking': state["show_tracking"] = request.json.get("track", True)
217
+ elif action == 'pause': state["paused"] = True
218
+ elif action == 'play': state["paused"] = False
219
+ elif action == 'seek': state["seek_to"] = request.json.get("value", 0.0)
220
+
221
+ return jsonify({"status": "ok"})
222
 
223
  def video_stream_gen(stream_id, source, location):
224
  cap = cv2.VideoCapture(source)
225
+ fps = cap.get(cv2.CAP_PROP_FPS)
226
+ if not fps or fps == 0: fps = 30.0
227
+ total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
228
+ is_live = str(source).startswith('http')
229
+
230
  frames_3d = []
231
  yolo_probs = []
232
  frame_count = 0
233
+ last_buffer = None
234
 
235
  while True:
 
 
 
236
  state = active_streams.get(stream_id)
237
  if not state: break
238
 
239
+ # Video Control: Seek
240
+ if state.get('seek_to') is not None:
241
+ target = int(state['seek_to'] * total_frames)
242
+ cap.set(cv2.CAP_PROP_POS_FRAMES, target)
243
+ state['seek_to'] = None
244
+ frames_3d.clear()
245
+ yolo_probs.clear()
246
+
247
+ # Video Control: Pause
248
+ if state.get('paused'):
249
+ time.sleep(0.1)
250
+ if last_buffer: yield (b'--frame\r\nContent-Type: image/jpeg\r\n\r\n' + last_buffer + b'\r\n')
251
+ continue
252
+
253
+ loop_start = time.time()
254
+ ret, frame = cap.read()
255
+
256
+ if not ret:
257
+ if total_frames > 0: state["progress"] = 100 # End of video
258
+ break
259
+
260
+ # Calculate progress
261
+ if total_frames > 0:
262
+ state['progress'] = (cap.get(cv2.CAP_PROP_POS_FRAMES) / total_frames) * 100
263
+
264
+ # AI Tracking Layer
265
  if state.get("show_tracking", True):
266
  track_res = model_tracker(frame, classes=[2, 3, 5, 7], verbose=False, conf=0.3)[0]
267
  display_frame = track_res.plot()
268
  else:
269
  display_frame = frame
270
 
271
+ # Brain / Severity Scanning
272
  if not state.get("final_decision"):
273
  res = model_yolo(frame, verbose=False)[0]
274
+
275
+ probs = np.zeros(4)
276
  if res.probs is not None:
277
+ data = res.probs.data.cpu().numpy()
278
+ length = min(len(data), 4)
279
+ probs[:length] = data[:length]
280
+ elif res.boxes is not None and len(res.boxes) > 0:
281
+ for box in res.boxes:
282
+ cls_id = int(box.cls[0].item())
283
+ if cls_id < 4: probs[cls_id] = max(probs[cls_id], float(box.conf[0].item()))
284
+
285
+ yolo_probs.append(probs)
286
+ if len(yolo_probs) > 10: yolo_probs.pop(0)
287
 
288
  f_3d = cv2.resize(frame, (112, 112))
289
  frames_3d.append(cv2.cvtColor(f_3d, cv2.COLOR_BGR2RGB))
 
300
  )).start()
301
 
302
  _, buffer = cv2.imencode('.jpg', display_frame)
303
+ last_buffer = buffer.tobytes()
304
+ yield (b'--frame\r\nContent-Type: image/jpeg\r\n\r\n' + last_buffer + b'\r\n')
305
  frame_count += 1
306
+
307
+ # 🚨 FIX: Force actual frame playback speed for local videos so AI has time to process 🚨
308
+ if not is_live:
309
+ elapsed = time.time() - loop_start
310
+ sleep_time = (1.0 / fps) - elapsed
311
+ if sleep_time > 0:
312
+ time.sleep(sleep_time)
313
 
314
  cap.release()
315
 
 
332
 
333
  prob = float(model_traffic.predict_proba(df)[0][1] * 100)
334
 
335
+ # Strict mapping as requested
336
  if prob >= 70: status = "Major"
337
  elif prob >= 35: status = "Moderate"
338
  else: status = "Minor"
339
 
340
+ return jsonify({"status": status})
 
 
 
341
  except Exception as e: return jsonify({"error": str(e)}), 500
342
 
343
  @app.route('/')