lokesh341 commited on
Commit
4fe77cf
·
1 Parent(s): 8cc6416

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -65
app.py CHANGED
@@ -26,6 +26,7 @@ from services.operations_maintenance.signage_check import process_signages
26
  from services.road_safety.barrier_check import process_barriers
27
  from services.road_safety.lighting_check import process_lighting
28
  from services.road_safety.accident_spot_check import process_accident_spots
 
29
  # Plantation services
30
  from services.plantation.plant_count import process_plants
31
  from services.plantation.plant_health import process_plant_health
@@ -40,7 +41,7 @@ logging.basicConfig(
40
 
41
  # Globals
42
  paused = False
43
- frame_rate = 0.1 # Faster frame rate for real-time feel
44
  frame_count = 0
45
  log_entries = []
46
  crack_counts = []
@@ -48,10 +49,10 @@ crack_severity_all = []
48
  last_frame = None
49
  last_detections = {}
50
  last_timestamp = ""
51
- last_detected_images = [] # Store up to 100+ frames with detections
52
  gps_coordinates = []
53
  video_loaded = False
54
- active_service = None # Track the active service category
55
 
56
  # Constants
57
  DEFAULT_VIDEO_PATH = "sample.mp4"
@@ -62,9 +63,6 @@ os.makedirs(CAPTURED_FRAMES_DIR, exist_ok=True)
62
  os.makedirs(OUTPUT_DIR, exist_ok=True)
63
 
64
  def initialize_video(video_file=None):
65
- """
66
- Initialize the video with the provided file or default path.
67
- """
68
  global video_loaded, log_entries
69
  release_video()
70
  video_path = DEFAULT_VIDEO_PATH
@@ -81,11 +79,7 @@ def initialize_video(video_file=None):
81
  return status
82
 
83
  def set_active_service(service_name, uc_val, om_val, rs_val, pl_val):
84
- """
85
- Set the active service category based on toggles.
86
- Only one service category can be active at a time.
87
- """
88
- global active_service, service_toggles
89
  toggles = {
90
  "under_construction": uc_val,
91
  "operations_maintenance": om_val,
@@ -93,14 +87,12 @@ def set_active_service(service_name, uc_val, om_val, rs_val, pl_val):
93
  "plantation": pl_val
94
  }
95
 
96
- # Ensure only one toggle is active
97
  active_count = sum(toggles.values())
98
  if active_count > 1:
99
  log_entries.append("Error: Only one service category can be active at a time.")
100
  logging.error("Multiple service categories enabled simultaneously.")
101
  return None, "Error: Please enable only one service category at a time."
102
 
103
- # Set active service
104
  for service, enabled in toggles.items():
105
  if enabled:
106
  active_service = service
@@ -114,16 +106,12 @@ def set_active_service(service_name, uc_val, om_val, rs_val, pl_val):
114
  return None, "No Service Category Enabled"
115
 
116
  def monitor_feed():
117
- """
118
- Main function to process video frames in real-time.
119
- Only the active service category processes the frame.
120
- """
121
  global paused, frame_count, last_frame, last_detections, last_timestamp, gps_coordinates, last_detected_images, video_loaded
122
 
123
  if not video_loaded:
124
  log_entries.append("Cannot start streaming: Video not loaded successfully.")
125
  logging.error("Video not loaded successfully.")
126
- return None, json.dumps({"error": "Video not loaded. Please upload a video file."}, indent=2), "\n".join(log_entries[-10:]), None, None, last_detected_images
127
 
128
  if paused and last_frame is not None:
129
  frame = last_frame.copy()
@@ -136,12 +124,10 @@ def monitor_feed():
136
  except RuntimeError as e:
137
  log_entries.append(f"Error: {str(e)}")
138
  logging.error(f"Frame retrieval error: {str(e)}")
139
- return None, json.dumps(last_detections, indent=2), "\n".join(log_entries[-10:]), None, None, last_detected_images
140
 
141
- # Initialize detected items list
142
  all_detected_items = []
143
 
144
- # Process only the active service category
145
  try:
146
  if active_service == "under_construction":
147
  earthwork_dets, frame = process_earthwork(frame)
@@ -160,7 +146,8 @@ def monitor_feed():
160
  barrier_dets, frame = process_barriers(frame)
161
  lighting_dets, frame = process_lighting(frame)
162
  accident_dets, frame = process_accident_spots(frame)
163
- all_detected_items.extend(barrier_dets + lighting_dets + accident_dets)
 
164
 
165
  elif active_service == "plantation":
166
  plant_dets, frame = process_plants(frame)
@@ -169,18 +156,15 @@ def monitor_feed():
169
  all_detected_items.extend(plant_dets + health_dets + missing_dets)
170
 
171
  else:
172
- # Fallback: Run generic detection if no service is active
173
  generic_dets, frame = process_generic(frame)
174
  all_detected_items.extend(generic_dets)
175
 
176
- # Optional: Run shadow detection (affects all modes for better accuracy)
177
  shadow_results = detect_shadows(frame)
178
  shadow_dets = shadow_results["detections"]
179
  frame = shadow_results["frame"]
180
  all_detected_items.extend(shadow_dets)
181
 
182
- # Optional: Run thermal processing if frame is grayscale (simulated check)
183
- if len(frame.shape) == 2: # Grayscale frame (simulating thermal input)
184
  thermal_results = process_thermal(frame)
185
  thermal_dets = thermal_results["detections"]
186
  frame = thermal_results["frame"]
@@ -191,7 +175,6 @@ def monitor_feed():
191
  logging.error(f"Processing error in {active_service}: {str(e)}")
192
  all_detected_items = []
193
 
194
- # Save frame with overlays
195
  try:
196
  cv2.imwrite(TEMP_IMAGE_PATH, frame, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
197
  except Exception as e:
@@ -200,11 +183,9 @@ def monitor_feed():
200
 
201
  metrics = update_metrics(all_detected_items)
202
 
203
- # Simulate GPS coordinates
204
  gps_coord = [17.385044 + random.uniform(-0.001, 0.001), 78.486671 + frame_count * 0.0001]
205
  gps_coordinates.append(gps_coord)
206
 
207
- # Save frame if there are detections (e.g., cracks, plants, etc.)
208
  detection_types = {item.get("type") for item in all_detected_items if "type" in item}
209
  if detection_types:
210
  try:
@@ -217,7 +198,6 @@ def monitor_feed():
217
  log_entries.append(f"Error saving captured frame: {str(e)}")
218
  logging.error(f"Error saving captured frame: {str(e)}")
219
 
220
- # Combine detections for Salesforce
221
  all_detections = {
222
  "items": all_detected_items,
223
  "metrics": metrics,
@@ -226,14 +206,12 @@ def monitor_feed():
226
  "gps_coordinates": gps_coord
227
  }
228
 
229
- # Dispatch to Salesforce
230
  try:
231
  dispatch_to_salesforce(all_detections, all_detections["timestamp"])
232
  except Exception as e:
233
  log_entries.append(f"Salesforce Dispatch Error: {str(e)}")
234
  logging.error(f"Salesforce dispatch error: {str(e)}")
235
 
236
- # Save annotated frame
237
  try:
238
  frame_path = os.path.join(OUTPUT_DIR, f"frame_{frame_count:04d}.jpg")
239
  cv2.imwrite(frame_path, frame)
@@ -246,9 +224,8 @@ def monitor_feed():
246
  last_frame = frame.copy()
247
  last_detections = metrics
248
 
249
- # Update logs and stats
250
- crack_detected = len([item for item in all_detected_items if item.get("type") == "crack"]) if active_service == "operations_maintenance" else 0
251
- if active_service == "operations_maintenance":
252
  crack_severity_all.extend([
253
  item["severity"]
254
  for item in all_detected_items
@@ -269,28 +246,25 @@ def monitor_feed():
269
  if len(crack_severity_all) > 500:
270
  crack_severity_all.pop(0)
271
 
272
- # Add frame count and timestamp to display
273
  frame = cv2.resize(last_frame, (640, 480))
274
  cv2.putText(frame, f"Frame: {frame_count}", (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
275
  cv2.putText(frame, f"{last_timestamp}", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
276
 
277
- # Generate charts (only for operations_maintenance)
278
  line_chart = None
279
  pie_chart = None
280
- if active_service == "operations_maintenance":
 
281
  line_chart = generate_line_chart()
282
  pie_chart = generate_pie_chart()
 
283
 
284
- return frame[:, :, ::-1], json.dumps(last_detections, indent=2), "\n".join(log_entries[-10:]), line_chart, pie_chart, last_detected_images
285
 
286
  def generate_line_chart():
287
- """
288
- Generate a line chart for crack counts over time using Chart.js.
289
- """
290
  if not crack_counts:
291
  return None
292
 
293
- data = crack_counts[-50:] # Last 50 frames
294
  labels = list(range(len(data)))
295
 
296
  return {
@@ -300,7 +274,7 @@ def generate_line_chart():
300
  "datasets": [{
301
  "label": "Cracks Over Time",
302
  "data": data,
303
- "borderColor": "#FF6347", # Tomato
304
  "backgroundColor": "rgba(255, 99, 71, 0.2)",
305
  "fill": True,
306
  "tension": 0.4
@@ -311,7 +285,7 @@ def generate_line_chart():
311
  "plugins": {
312
  "title": {
313
  "display": True,
314
- "text": "Cracks Over Time"
315
  }
316
  },
317
  "scales": {
@@ -333,13 +307,10 @@ def generate_line_chart():
333
  }
334
 
335
  def generate_pie_chart():
336
- """
337
- Generate a pie chart for crack severity distribution using Chart.js.
338
- """
339
  if not crack_severity_all:
340
  return None
341
 
342
- count = Counter(crack_severity_all[-200:]) # Last 200 cracks
343
  labels = list(count.keys())
344
  sizes = list(count.values())
345
 
@@ -350,9 +321,9 @@ def generate_pie_chart():
350
  "datasets": [{
351
  "data": sizes,
352
  "backgroundColor": [
353
- "#FF6347", # Tomato
354
- "#4682B4", # SteelBlue
355
- "#FFD700" # Gold
356
  ]
357
  }]
358
  },
@@ -361,7 +332,7 @@ def generate_pie_chart():
361
  "plugins": {
362
  "title": {
363
  "display": True,
364
- "text": "Crack Severity Distribution"
365
  },
366
  "legend": {
367
  "position": "top"
@@ -370,6 +341,57 @@ def generate_pie_chart():
370
  }
371
  }
372
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  # Gradio UI
374
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green")) as app:
375
  gr.Markdown(
@@ -379,7 +401,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
379
  """
380
  )
381
 
382
- # Video upload section
383
  with gr.Row():
384
  with gr.Column(scale=3):
385
  video_input = gr.File(label="Upload Video File (e.g., sample.mp4)", file_types=["video"])
@@ -391,7 +412,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
391
  interactive=False
392
  )
393
 
394
- # Toggles for service categories with status indicators
395
  with gr.Row():
396
  with gr.Column():
397
  uc_toggle = gr.Checkbox(label="Enable Under Construction Services", value=False)
@@ -418,8 +438,9 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
418
  with gr.Column(scale=2):
419
  logs_output = gr.Textbox(label="Live Logs", lines=8, interactive=False)
420
  with gr.Column(scale=1):
421
- chart_output = gr.Plot(label="Crack Trend (Operations Maintenance Only)")
422
- pie_output = gr.Plot(label="Crack Severity (Operations Maintenance Only)")
 
423
 
424
  with gr.Row():
425
  captured_images = gr.Gallery(label="Detected Frames (Last 100+)", columns=4, rows=25, height="auto")
@@ -429,7 +450,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
429
  resume_btn = gr.Button("▶️ Resume", variant="primary")
430
  frame_slider = gr.Slider(0.05, 1.0, value=0.1, label="Frame Interval (seconds)", step=0.05)
431
 
432
- # Add some custom CSS for better UX
433
  gr.HTML("""
434
  <style>
435
  #live-feed {
@@ -459,7 +479,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
459
  global frame_rate
460
  frame_rate = val
461
 
462
- # Initialize video on app load
463
  video_status.value = initialize_video()
464
 
465
  load_button.click(
@@ -468,7 +487,6 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
468
  outputs=[video_status]
469
  )
470
 
471
- # Toggle change events
472
  def update_toggles(uc_val, om_val, rs_val, pl_val):
473
  active, status_message = set_active_service("toggle", uc_val, om_val, rs_val, pl_val)
474
  uc_status_val = "Enabled" if active == "under_construction" else "Disabled"
@@ -493,16 +511,16 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green"))
493
  def streaming_loop():
494
  while True:
495
  if not video_loaded:
496
- yield None, json.dumps({"error": "Video not loaded. Please upload a video file."}, indent=2), "\n".join(log_entries[-10:]), None, None, last_detected_images
497
  else:
498
- frame, detections, logs, line_chart, pie_chart, captured = monitor_feed()
499
  if frame is None:
500
- yield None, detections, logs, line_chart, pie_chart, captured
501
  else:
502
- yield frame, detections, logs, line_chart, pie_chart, captured
503
  time.sleep(frame_rate)
504
 
505
- app.load(streaming_loop, outputs=[video_output, detections_output, logs_output, chart_output, pie_output, captured_images])
506
 
507
  if __name__ == "__main__":
508
  app.launch(share=True)
 
26
  from services.road_safety.barrier_check import process_barriers
27
  from services.road_safety.lighting_check import process_lighting
28
  from services.road_safety.accident_spot_check import process_accident_spots
29
+ from services.road_safety.pothole_crack_detection import detect_potholes_and_cracks
30
  # Plantation services
31
  from services.plantation.plant_count import process_plants
32
  from services.plantation.plant_health import process_plant_health
 
41
 
42
  # Globals
43
  paused = False
44
+ frame_rate = 0.1
45
  frame_count = 0
46
  log_entries = []
47
  crack_counts = []
 
49
  last_frame = None
50
  last_detections = {}
51
  last_timestamp = ""
52
+ last_detected_images = []
53
  gps_coordinates = []
54
  video_loaded = False
55
+ active_service = None
56
 
57
  # Constants
58
  DEFAULT_VIDEO_PATH = "sample.mp4"
 
63
  os.makedirs(OUTPUT_DIR, exist_ok=True)
64
 
65
  def initialize_video(video_file=None):
 
 
 
66
  global video_loaded, log_entries
67
  release_video()
68
  video_path = DEFAULT_VIDEO_PATH
 
79
  return status
80
 
81
  def set_active_service(service_name, uc_val, om_val, rs_val, pl_val):
82
+ global active_service
 
 
 
 
83
  toggles = {
84
  "under_construction": uc_val,
85
  "operations_maintenance": om_val,
 
87
  "plantation": pl_val
88
  }
89
 
 
90
  active_count = sum(toggles.values())
91
  if active_count > 1:
92
  log_entries.append("Error: Only one service category can be active at a time.")
93
  logging.error("Multiple service categories enabled simultaneously.")
94
  return None, "Error: Please enable only one service category at a time."
95
 
 
96
  for service, enabled in toggles.items():
97
  if enabled:
98
  active_service = service
 
106
  return None, "No Service Category Enabled"
107
 
108
  def monitor_feed():
 
 
 
 
109
  global paused, frame_count, last_frame, last_detections, last_timestamp, gps_coordinates, last_detected_images, video_loaded
110
 
111
  if not video_loaded:
112
  log_entries.append("Cannot start streaming: Video not loaded successfully.")
113
  logging.error("Video not loaded successfully.")
114
+ return None, json.dumps({"error": "Video not loaded. Please upload a video file."}, indent=2), "\n".join(log_entries[-10:]), None, None, None, last_detected_images
115
 
116
  if paused and last_frame is not None:
117
  frame = last_frame.copy()
 
124
  except RuntimeError as e:
125
  log_entries.append(f"Error: {str(e)}")
126
  logging.error(f"Frame retrieval error: {str(e)}")
127
+ return None, json.dumps(last_detections, indent=2), "\n".join(log_entries[-10:]), None, None, None, last_detected_images
128
 
 
129
  all_detected_items = []
130
 
 
131
  try:
132
  if active_service == "under_construction":
133
  earthwork_dets, frame = process_earthwork(frame)
 
146
  barrier_dets, frame = process_barriers(frame)
147
  lighting_dets, frame = process_lighting(frame)
148
  accident_dets, frame = process_accident_spots(frame)
149
+ pothole_crack_dets, frame = detect_potholes_and_cracks(frame)
150
+ all_detected_items.extend(barrier_dets + lighting_dets + accident_dets + pothole_crack_dets)
151
 
152
  elif active_service == "plantation":
153
  plant_dets, frame = process_plants(frame)
 
156
  all_detected_items.extend(plant_dets + health_dets + missing_dets)
157
 
158
  else:
 
159
  generic_dets, frame = process_generic(frame)
160
  all_detected_items.extend(generic_dets)
161
 
 
162
  shadow_results = detect_shadows(frame)
163
  shadow_dets = shadow_results["detections"]
164
  frame = shadow_results["frame"]
165
  all_detected_items.extend(shadow_dets)
166
 
167
+ if len(frame.shape) == 2:
 
168
  thermal_results = process_thermal(frame)
169
  thermal_dets = thermal_results["detections"]
170
  frame = thermal_results["frame"]
 
175
  logging.error(f"Processing error in {active_service}: {str(e)}")
176
  all_detected_items = []
177
 
 
178
  try:
179
  cv2.imwrite(TEMP_IMAGE_PATH, frame, [int(cv2.IMWRITE_JPEG_QUALITY), 95])
180
  except Exception as e:
 
183
 
184
  metrics = update_metrics(all_detected_items)
185
 
 
186
  gps_coord = [17.385044 + random.uniform(-0.001, 0.001), 78.486671 + frame_count * 0.0001]
187
  gps_coordinates.append(gps_coord)
188
 
 
189
  detection_types = {item.get("type") for item in all_detected_items if "type" in item}
190
  if detection_types:
191
  try:
 
198
  log_entries.append(f"Error saving captured frame: {str(e)}")
199
  logging.error(f"Error saving captured frame: {str(e)}")
200
 
 
201
  all_detections = {
202
  "items": all_detected_items,
203
  "metrics": metrics,
 
206
  "gps_coordinates": gps_coord
207
  }
208
 
 
209
  try:
210
  dispatch_to_salesforce(all_detections, all_detections["timestamp"])
211
  except Exception as e:
212
  log_entries.append(f"Salesforce Dispatch Error: {str(e)}")
213
  logging.error(f"Salesforce dispatch error: {str(e)}")
214
 
 
215
  try:
216
  frame_path = os.path.join(OUTPUT_DIR, f"frame_{frame_count:04d}.jpg")
217
  cv2.imwrite(frame_path, frame)
 
224
  last_frame = frame.copy()
225
  last_detections = metrics
226
 
227
+ crack_detected = len([item for item in all_detected_items if item.get("type") == "crack"]) if active_service in ["operations_maintenance", "road_safety"] else 0
228
+ if active_service in ["operations_maintenance", "road_safety"]:
 
229
  crack_severity_all.extend([
230
  item["severity"]
231
  for item in all_detected_items
 
246
  if len(crack_severity_all) > 500:
247
  crack_severity_all.pop(0)
248
 
 
249
  frame = cv2.resize(last_frame, (640, 480))
250
  cv2.putText(frame, f"Frame: {frame_count}", (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
251
  cv2.putText(frame, f"{last_timestamp}", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
252
 
 
253
  line_chart = None
254
  pie_chart = None
255
+ bar_chart = None
256
+ if active_service in ["operations_maintenance", "road_safety"]:
257
  line_chart = generate_line_chart()
258
  pie_chart = generate_pie_chart()
259
+ bar_chart = generate_bar_chart()
260
 
261
+ return frame[:, :, ::-1], json.dumps(last_detections, indent=2), "\n".join(log_entries[-10:]), line_chart, pie_chart, bar_chart, last_detected_images
262
 
263
  def generate_line_chart():
 
 
 
264
  if not crack_counts:
265
  return None
266
 
267
+ data = crack_counts[-50:]
268
  labels = list(range(len(data)))
269
 
270
  return {
 
274
  "datasets": [{
275
  "label": "Cracks Over Time",
276
  "data": data,
277
+ "borderColor": "#FF6347",
278
  "backgroundColor": "rgba(255, 99, 71, 0.2)",
279
  "fill": True,
280
  "tension": 0.4
 
285
  "plugins": {
286
  "title": {
287
  "display": True,
288
+ "text": "Crack Trend"
289
  }
290
  },
291
  "scales": {
 
307
  }
308
 
309
  def generate_pie_chart():
 
 
 
310
  if not crack_severity_all:
311
  return None
312
 
313
+ count = Counter(crack_severity_all[-200:])
314
  labels = list(count.keys())
315
  sizes = list(count.values())
316
 
 
321
  "datasets": [{
322
  "data": sizes,
323
  "backgroundColor": [
324
+ "#FF6347",
325
+ "#4682B4",
326
+ "#FFD700"
327
  ]
328
  }]
329
  },
 
332
  "plugins": {
333
  "title": {
334
  "display": True,
335
+ "text": "Crack Severity"
336
  },
337
  "legend": {
338
  "position": "top"
 
341
  }
342
  }
343
 
344
+ def generate_bar_chart():
345
+ if not crack_severity_all:
346
+ return None
347
+
348
+ count = Counter(crack_severity_all[-200:])
349
+ labels = list(count.keys())
350
+ sizes = list(count.values())
351
+
352
+ return {
353
+ "type": "bar",
354
+ "data": {
355
+ "labels": labels,
356
+ "datasets": [{
357
+ "label": "Severity Distribution",
358
+ "data": sizes,
359
+ "backgroundColor": [
360
+ "#FF6347",
361
+ "#4682B4",
362
+ "#FFD700"
363
+ ]
364
+ }]
365
+ },
366
+ "options": {
367
+ "responsive": True,
368
+ "plugins": {
369
+ "title": {
370
+ "display": True,
371
+ "text": "Severity Distribution"
372
+ },
373
+ "legend": {
374
+ "display": False
375
+ }
376
+ },
377
+ "scales": {
378
+ "y": {
379
+ "beginAtZero": True,
380
+ "title": {
381
+ "display": True,
382
+ "text": "Count"
383
+ }
384
+ },
385
+ "x": {
386
+ "title": {
387
+ "display": True,
388
+ "text": "Severity"
389
+ }
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
  # Gradio UI
396
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="green")) as app:
397
  gr.Markdown(
 
401
  """
402
  )
403
 
 
404
  with gr.Row():
405
  with gr.Column(scale=3):
406
  video_input = gr.File(label="Upload Video File (e.g., sample.mp4)", file_types=["video"])
 
412
  interactive=False
413
  )
414
 
 
415
  with gr.Row():
416
  with gr.Column():
417
  uc_toggle = gr.Checkbox(label="Enable Under Construction Services", value=False)
 
438
  with gr.Column(scale=2):
439
  logs_output = gr.Textbox(label="Live Logs", lines=8, interactive=False)
440
  with gr.Column(scale=1):
441
+ chart_output = gr.Plot(label="Crack Trend (Operations Maintenance & Road Safety)")
442
+ pie_output = gr.Plot(label="Crack Severity (Operations Maintenance & Road Safety)")
443
+ bar_output = gr.Plot(label="Severity Distribution (Operations Maintenance & Road Safety)")
444
 
445
  with gr.Row():
446
  captured_images = gr.Gallery(label="Detected Frames (Last 100+)", columns=4, rows=25, height="auto")
 
450
  resume_btn = gr.Button("▶️ Resume", variant="primary")
451
  frame_slider = gr.Slider(0.05, 1.0, value=0.1, label="Frame Interval (seconds)", step=0.05)
452
 
 
453
  gr.HTML("""
454
  <style>
455
  #live-feed {
 
479
  global frame_rate
480
  frame_rate = val
481
 
 
482
  video_status.value = initialize_video()
483
 
484
  load_button.click(
 
487
  outputs=[video_status]
488
  )
489
 
 
490
  def update_toggles(uc_val, om_val, rs_val, pl_val):
491
  active, status_message = set_active_service("toggle", uc_val, om_val, rs_val, pl_val)
492
  uc_status_val = "Enabled" if active == "under_construction" else "Disabled"
 
511
  def streaming_loop():
512
  while True:
513
  if not video_loaded:
514
+ yield None, json.dumps({"error": "Video not loaded. Please upload a video file."}, indent=2), "\n".join(log_entries[-10:]), None, None, None, last_detected_images
515
  else:
516
+ frame, detections, logs, line_chart, pie_chart, bar_chart, captured = monitor_feed()
517
  if frame is None:
518
+ yield None, detections, logs, line_chart, pie_chart, bar_chart, captured
519
  else:
520
+ yield frame, detections, logs, line_chart, pie_chart, bar_chart, captured
521
  time.sleep(frame_rate)
522
 
523
+ app.load(streaming_loop, outputs=[video_output, detections_output, logs_output, chart_output, pie_output, bar_output, captured_images])
524
 
525
  if __name__ == "__main__":
526
  app.launch(share=True)