matrice 1.0.99133__py3-none-any.whl → 1.0.99135__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,7 +31,7 @@ class ConcreteCrackConfig(BaseConfig):
31
31
  smoothing_confidence_range_factor: float = 0.5
32
32
 
33
33
  #confidence thresholds
34
- confidence_threshold: float = 0.6
34
+ confidence_threshold: float = 0.2
35
35
 
36
36
  usecase_categories: List[str] = field(
37
37
  default_factory=lambda: ['Cracks']
@@ -55,6 +55,7 @@ class ConcreteCrackUseCase(BaseProcessor):
55
55
  CATEGORY_DISPLAY = {
56
56
  "Cracks": "Cracks",
57
57
  }
58
+
58
59
  def __init__(self):
59
60
  super().__init__("concrete_crack_detection")
60
61
  self.category = "general"
@@ -63,7 +64,7 @@ class ConcreteCrackUseCase(BaseProcessor):
63
64
  self.CASE_VERSION: Optional[str] = '1.3'
64
65
 
65
66
  # List of categories to track
66
- self.target_categories = ["Cracks"]
67
+ self.target_categories = ['Cracks']
67
68
 
68
69
  # Initialize smoothing tracker
69
70
  self.smoothing_tracker = None
@@ -106,6 +107,8 @@ class ConcreteCrackUseCase(BaseProcessor):
106
107
  input_format = match_results_structure(data)
107
108
  context.input_format = input_format
108
109
  context.confidence_threshold = config.confidence_threshold
110
+
111
+
109
112
 
110
113
  if config.confidence_threshold is not None:
111
114
  processed_data = filter_by_confidence(data, config.confidence_threshold)
@@ -114,15 +117,17 @@ class ConcreteCrackUseCase(BaseProcessor):
114
117
  processed_data = data
115
118
 
116
119
  self.logger.debug(f"Did not apply confidence filtering with threshold since nothing was provided")
117
-
120
+ print(processed_data)
118
121
  # Step 2: Apply category mapping if provided
119
122
  if config.index_to_category:
120
123
  processed_data = apply_category_mapping(processed_data, config.index_to_category)
121
124
  self.logger.debug("Applied category mapping")
122
-
125
+ print(processed_data)
123
126
  if config.target_categories:
124
127
  processed_data = [d for d in processed_data if d.get('category') in self.target_categories]
125
128
  self.logger.debug(f"Applied category filtering")
129
+
130
+ print(processed_data)
126
131
 
127
132
  # Apply bbox smoothing if enabled
128
133
  if config.enable_smoothing:
@@ -203,6 +208,7 @@ class ConcreteCrackUseCase(BaseProcessor):
203
208
  "human_text": summary}
204
209
  }
205
210
 
211
+
206
212
  context.mark_completed()
207
213
 
208
214
  # Build result object following the new pattern
@@ -348,7 +354,7 @@ class ConcreteCrackUseCase(BaseProcessor):
348
354
  human_text_lines.append(f"\tSeverity Level: {(self.CASE_TYPE,level)}")
349
355
  human_text = "\n".join(human_text_lines)
350
356
 
351
- alert_settings=[]
357
+ alert_settings = []
352
358
  if config.alert_config and hasattr(config.alert_config, 'alert_type'):
353
359
  alert_settings.append({
354
360
  "alert_type": getattr(config.alert_config, 'alert_type', ['Default']) if hasattr(config.alert_config, 'alert_type') else ['Default'],
@@ -369,7 +375,7 @@ class ConcreteCrackUseCase(BaseProcessor):
369
375
  else:
370
376
  self._ascending_alert_list.append(0)
371
377
  incidents.append({})
372
-
378
+
373
379
  return incidents
374
380
 
375
381
  def _generate_tracking_stats(
@@ -399,7 +405,7 @@ class ConcreteCrackUseCase(BaseProcessor):
399
405
  # Create high precision timestamps for input_timestamp and reset_timestamp
400
406
  high_precision_start_timestamp = self._get_current_timestamp_str(stream_info, precision=True)
401
407
  high_precision_reset_timestamp = self._get_start_timestamp_str(stream_info, precision=True)
402
- print(counting_summary)
408
+
403
409
 
404
410
  # Build total_counts array in expected format
405
411
  total_counts = []
@@ -409,7 +415,7 @@ class ConcreteCrackUseCase(BaseProcessor):
409
415
  "category": cat,
410
416
  "count": count
411
417
  })
412
- print(total_counts)
418
+
413
419
  # Build current_counts array in expected format
414
420
  current_counts = []
415
421
  for cat, count in per_category_count.items():
@@ -418,7 +424,7 @@ class ConcreteCrackUseCase(BaseProcessor):
418
424
  "category": cat,
419
425
  "count": count
420
426
  })
421
- print(current_counts)
427
+
422
428
  # Prepare detections without confidence scores (as per eg.json)
423
429
  detections = []
424
430
  for detection in counting_summary.get("detections", []):
@@ -450,7 +456,7 @@ class ConcreteCrackUseCase(BaseProcessor):
450
456
  getattr(config.alert_config, 'alert_value', ['JSON']) if hasattr(config.alert_config, 'alert_value') else ['JSON'])
451
457
  }
452
458
  })
453
-
459
+
454
460
  # Generate human_text in expected format
455
461
  human_text_lines = [f"Tracking Statistics:"]
456
462
  human_text_lines.append(f"CURRENT FRAME @ {current_timestamp}")
@@ -470,7 +476,7 @@ class ConcreteCrackUseCase(BaseProcessor):
470
476
  human_text_lines.append("Alerts: None")
471
477
 
472
478
  human_text = "\n".join(human_text_lines)
473
- reset_settings=[
479
+ reset_settings = [
474
480
  {
475
481
  "interval_type": "daily",
476
482
  "reset_time": {
@@ -182,53 +182,90 @@ class FlareAnalysisUseCase(BaseProcessor):
182
182
  return {cat: len(ids) for cat, ids in self._per_category_total_track_ids.items()}
183
183
 
184
184
  def _format_timestamp_for_video(self, timestamp: float) -> str:
185
+ """Format timestamp for video chunks (HH:MM:SS.ms format)."""
185
186
  hours = int(timestamp // 3600)
186
187
  minutes = int((timestamp % 3600) // 60)
187
- seconds = timestamp % 60
188
- return f"{hours:02d}:{minutes:02d}:{seconds:06.2f}"
188
+ seconds = round(float(timestamp % 60),2)
189
+ return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
189
190
 
190
191
  def _format_timestamp_for_stream(self, timestamp: float, precision: bool = False) -> str:
191
192
  dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
192
193
  return dt.strftime("%Y-%m-%d-%H:%M:%S.%f UTC" if precision else "%Y:%m:%d %H:%M:%S")
193
194
 
194
- def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision: bool = False) -> str:
195
+ def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
196
+ """Get formatted current timestamp based on stream type."""
195
197
  if not stream_info:
196
- return "00:00:00.00" if not precision else "00:00:00.000000 UTC"
197
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
198
- stream_time_str = stream_info.get("video_timestamp", "")
199
- return stream_time_str[:8] if not precision else stream_time_str
198
+ return "00:00:00.00"
199
+ # is_video_chunk = stream_info.get("input_settings", {}).get("is_video_chunk", False)
200
+ if precision:
201
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
202
+ if frame_id:
203
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
204
+ else:
205
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
206
+ stream_time_str = self._format_timestamp_for_video(start_time)
207
+ return stream_time_str
208
+ else:
209
+ return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
210
+
211
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
212
+ if frame_id:
213
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
214
+ else:
215
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
216
+ stream_time_str = self._format_timestamp_for_video(start_time)
217
+ return stream_time_str
200
218
  else:
201
- stream_time_str = stream_info.get("stream_time", "")
219
+ # For streams, use stream_time from stream_info
220
+ stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
202
221
  if stream_time_str:
222
+ # Parse the high precision timestamp string to get timestamp
203
223
  try:
224
+ # Remove " UTC" suffix and parse
204
225
  timestamp_str = stream_time_str.replace(" UTC", "")
205
226
  dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
206
227
  timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
207
- return self._format_timestamp_for_stream(timestamp, precision)
228
+ return self._format_timestamp_for_stream(timestamp)
208
229
  except:
209
- return self._format_timestamp_for_stream(time.time(), precision)
210
- return self._format_timestamp_for_stream(time.time(), precision)
230
+ # Fallback to current time if parsing fails
231
+ return self._format_timestamp_for_stream(time.time())
232
+ else:
233
+ return self._format_timestamp_for_stream(time.time())
211
234
 
212
- def _get_start_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision: bool = False) -> str:
235
+ def _get_start_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False) -> str:
236
+ """Get formatted start timestamp for 'TOTAL SINCE' based on stream type."""
213
237
  if not stream_info:
214
- return "00:00:00" if not precision else "00:00:00.000000 UTC"
215
- is_video_chunk = stream_info.get("input_settings", {}).get("is_video_chunk", False)
216
- if is_video_chunk or stream_info.get("video_format") is not None:
217
- return "00:00:00" if not precision else "00:00:00.000000 UTC"
218
- if self._tracking_start_time is None:
219
- stream_time_str = stream_info.get("stream_time", "")
220
- if stream_time_str:
221
- try:
222
- timestamp_str = stream_time_str.replace(" UTC", "")
223
- dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
224
- self._tracking_start_time = dt.replace(tzinfo=timezone.utc).timestamp()
225
- except:
226
- self._tracking_start_time = time.time()
238
+ return "00:00:00"
239
+ if precision:
240
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
241
+ return "00:00:00"
227
242
  else:
228
- self._tracking_start_time = time.time()
229
- dt = datetime.fromtimestamp(self._tracking_start_time, tz=timezone.utc)
230
- dt = dt.replace(minute=0, second=0, microsecond=0)
231
- return dt.strftime("%Y:%m:%d %H:%M:%S" if not precision else "%Y-%m-%d-%H:%M:%S.%f UTC")
243
+ return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
244
+
245
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
246
+ # If video format, start from 00:00:00
247
+ return "00:00:00"
248
+ else:
249
+ # For streams, use tracking start time or current time with minutes/seconds reset
250
+ if self._tracking_start_time is None:
251
+ # Try to extract timestamp from stream_time string
252
+ stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
253
+ if stream_time_str:
254
+ try:
255
+ # Remove " UTC" suffix and parse
256
+ timestamp_str = stream_time_str.replace(" UTC", "")
257
+ dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
258
+ self._tracking_start_time = dt.replace(tzinfo=timezone.utc).timestamp()
259
+ except:
260
+ # Fallback to current time if parsing fails
261
+ self._tracking_start_time = time.time()
262
+ else:
263
+ self._tracking_start_time = time.time()
264
+
265
+ dt = datetime.fromtimestamp(self._tracking_start_time, tz=timezone.utc)
266
+ # Reset minutes and seconds to 00:00 for "TOTAL SINCE" format
267
+ dt = dt.replace(minute=0, second=0, microsecond=0)
268
+ return dt.strftime('%Y:%m:%d %H:%M:%S')
232
269
 
233
270
  def _get_track_ids_info(self, detections: List[Dict]) -> Dict[str, Any]:
234
271
  frame_track_ids = set(det.get('track_id') for det in detections if det.get('track_id') is not None)
@@ -514,67 +514,89 @@ class TrafficSignMonitoringUseCase(BaseProcessor):
514
514
  return {cat: len(ids) for cat, ids in getattr(self, '_per_category_total_track_ids', {}).items()}
515
515
 
516
516
  def _format_timestamp_for_video(self, timestamp: float) -> str:
517
- """Format timestamp for video chunks."""
517
+ """Format timestamp for video chunks (HH:MM:SS.ms format)."""
518
518
  hours = int(timestamp // 3600)
519
519
  minutes = int((timestamp % 3600) // 60)
520
- seconds = timestamp % 60
521
- return f"{hours:02d}:{minutes:02d}:{seconds:06.2f}"
520
+ seconds = round(float(timestamp % 60),2)
521
+ return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
522
522
 
523
523
  def _format_timestamp_for_stream(self, timestamp: float) -> str:
524
524
  """Format timestamp for streams."""
525
525
  dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
526
526
  return dt.strftime('%Y:%m:%d %H:%M:%S')
527
527
 
528
- def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False) -> str:
529
- """Get formatted current timestamp."""
528
+ def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
529
+ """Get formatted current timestamp based on stream type."""
530
530
  if not stream_info:
531
531
  return "00:00:00.00"
532
+ # is_video_chunk = stream_info.get("input_settings", {}).get("is_video_chunk", False)
532
533
  if precision:
533
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
534
- stream_time_str = stream_info.get("video_timestamp", "")
535
- return stream_time_str[:8]
534
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
535
+ if frame_id:
536
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
537
+ else:
538
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
539
+ stream_time_str = self._format_timestamp_for_video(start_time)
540
+ return stream_time_str
536
541
  else:
537
542
  return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
538
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
539
- stream_time_str = stream_info.get("video_timestamp", "")
540
- return stream_time_str[:8]
543
+
544
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
545
+ if frame_id:
546
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
547
+ else:
548
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
549
+ stream_time_str = self._format_timestamp_for_video(start_time)
550
+ return stream_time_str
541
551
  else:
542
- stream_time_str = stream_info.get("stream_time", "")
552
+ # For streams, use stream_time from stream_info
553
+ stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
543
554
  if stream_time_str:
555
+ # Parse the high precision timestamp string to get timestamp
544
556
  try:
557
+ # Remove " UTC" suffix and parse
545
558
  timestamp_str = stream_time_str.replace(" UTC", "")
546
559
  dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
547
560
  timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
548
561
  return self._format_timestamp_for_stream(timestamp)
549
562
  except:
563
+ # Fallback to current time if parsing fails
550
564
  return self._format_timestamp_for_stream(time.time())
551
565
  else:
552
566
  return self._format_timestamp_for_stream(time.time())
553
567
 
554
568
  def _get_start_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False) -> str:
555
- """Get formatted start timestamp."""
569
+ """Get formatted start timestamp for 'TOTAL SINCE' based on stream type."""
556
570
  if not stream_info:
557
571
  return "00:00:00"
558
572
  if precision:
559
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
573
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
560
574
  return "00:00:00"
561
575
  else:
562
576
  return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
563
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
577
+
578
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
579
+ # If video format, start from 00:00:00
564
580
  return "00:00:00"
565
581
  else:
582
+ # For streams, use tracking start time or current time with minutes/seconds reset
566
583
  if self._tracking_start_time is None:
567
- stream_time_str = stream_info.get("stream_time", "")
584
+ # Try to extract timestamp from stream_time string
585
+ stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
568
586
  if stream_time_str:
569
587
  try:
588
+ # Remove " UTC" suffix and parse
570
589
  timestamp_str = stream_time_str.replace(" UTC", "")
571
590
  dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
572
591
  self._tracking_start_time = dt.replace(tzinfo=timezone.utc).timestamp()
573
592
  except:
593
+ # Fallback to current time if parsing fails
574
594
  self._tracking_start_time = time.time()
575
595
  else:
576
596
  self._tracking_start_time = time.time()
597
+
577
598
  dt = datetime.fromtimestamp(self._tracking_start_time, tz=timezone.utc)
599
+ # Reset minutes and seconds to 00:00 for "TOTAL SINCE" format
578
600
  dt = dt.replace(minute=0, second=0, microsecond=0)
579
601
  return dt.strftime('%Y:%m:%d %H:%M:%S')
580
602
 
@@ -426,63 +426,88 @@ class WeaponDetectionUseCase(BaseProcessor):
426
426
  return {cat: len(ids) for cat, ids in getattr(self, '_per_category_total_track_ids', {}).items()}
427
427
 
428
428
  def _format_timestamp_for_video(self, timestamp: float) -> str:
429
+ """Format timestamp for video chunks (HH:MM:SS.ms format)."""
429
430
  hours = int(timestamp // 3600)
430
431
  minutes = int((timestamp % 3600) // 60)
431
- seconds = timestamp % 60
432
- return f"{hours:02d}:{minutes:02d}:{seconds:06.2f}"
432
+ seconds = round(float(timestamp % 60),2)
433
+ return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
433
434
 
434
435
  def _format_timestamp_for_stream(self, timestamp: float) -> str:
435
436
  dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
436
437
  return dt.strftime('%Y:%m:%d %H:%M:%S')
437
438
 
438
- def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False) -> str:
439
+ def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
440
+ """Get formatted current timestamp based on stream type."""
439
441
  if not stream_info:
440
442
  return "00:00:00.00"
443
+ # is_video_chunk = stream_info.get("input_settings", {}).get("is_video_chunk", False)
441
444
  if precision:
442
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
443
- stream_time_str = stream_info.get("video_timestamp", "")
444
- return stream_time_str[:8]
445
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
446
+ if frame_id:
447
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
448
+ else:
449
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
450
+ stream_time_str = self._format_timestamp_for_video(start_time)
451
+ return stream_time_str
445
452
  else:
446
453
  return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
447
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
448
- stream_time_str = stream_info.get("video_timestamp", "")
449
- return stream_time_str[:8]
454
+
455
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
456
+ if frame_id:
457
+ start_time = int(frame_id)/stream_info.get("input_settings", {}).get("original_fps", 30)
458
+ else:
459
+ start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
460
+ stream_time_str = self._format_timestamp_for_video(start_time)
461
+ return stream_time_str
450
462
  else:
451
- stream_time_str = stream_info.get("stream_time", "")
463
+ # For streams, use stream_time from stream_info
464
+ stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
452
465
  if stream_time_str:
466
+ # Parse the high precision timestamp string to get timestamp
453
467
  try:
468
+ # Remove " UTC" suffix and parse
454
469
  timestamp_str = stream_time_str.replace(" UTC", "")
455
470
  dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
456
471
  timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
457
472
  return self._format_timestamp_for_stream(timestamp)
458
473
  except:
474
+ # Fallback to current time if parsing fails
459
475
  return self._format_timestamp_for_stream(time.time())
460
476
  else:
461
477
  return self._format_timestamp_for_stream(time.time())
462
478
 
463
479
  def _get_start_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False) -> str:
480
+ """Get formatted start timestamp for 'TOTAL SINCE' based on stream type."""
464
481
  if not stream_info:
465
482
  return "00:00:00"
466
483
  if precision:
467
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
484
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
468
485
  return "00:00:00"
469
486
  else:
470
487
  return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
471
- if stream_info.get("input_settings", {}).get("stream_type", "video_file") == "video_file":
488
+
489
+ if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
490
+ # If video format, start from 00:00:00
472
491
  return "00:00:00"
473
492
  else:
493
+ # For streams, use tracking start time or current time with minutes/seconds reset
474
494
  if self._tracking_start_time is None:
475
- stream_time_str = stream_info.get("stream_time", "")
495
+ # Try to extract timestamp from stream_time string
496
+ stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
476
497
  if stream_time_str:
477
498
  try:
499
+ # Remove " UTC" suffix and parse
478
500
  timestamp_str = stream_time_str.replace(" UTC", "")
479
501
  dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
480
502
  self._tracking_start_time = dt.replace(tzinfo=timezone.utc).timestamp()
481
503
  except:
504
+ # Fallback to current time if parsing fails
482
505
  self._tracking_start_time = time.time()
483
506
  else:
484
507
  self._tracking_start_time = time.time()
508
+
485
509
  dt = datetime.fromtimestamp(self._tracking_start_time, tz=timezone.utc)
510
+ # Reset minutes and seconds to 00:00 for "TOTAL SINCE" format
486
511
  dt = dt.replace(minute=0, second=0, microsecond=0)
487
512
  return dt.strftime('%Y:%m:%d %H:%M:%S')
488
513
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrice
3
- Version: 1.0.99133
3
+ Version: 1.0.99135
4
4
  Summary: SDK for connecting to matrice.ai services
5
5
  Home-page: https://github.com/matrice-ai/python-sdk
6
6
  Author: Matrice.ai
@@ -166,7 +166,7 @@ matrice/deploy/utils/post_processing/usecases/chicken_pose_detection.py,sha256=-
166
166
  matrice/deploy/utils/post_processing/usecases/child_monitoring.py,sha256=z3oymoqq4hDGwA8MkdEONZW_Vx5CAZmvzZaNLsqmCfw,39380
167
167
  matrice/deploy/utils/post_processing/usecases/color_detection.py,sha256=Z8-akjy8a7f8YyiOzXu_Zi1Km30v-TRrymDqQOPpJ_8,43277
168
168
  matrice/deploy/utils/post_processing/usecases/color_map_utils.py,sha256=SP-AEVcjLmL8rxblu-ixqUJC2fqlcr7ab4hWo4Fcr_k,2677
169
- matrice/deploy/utils/post_processing/usecases/concrete_crack_detection.py,sha256=gz6uNgxwyJiB26zMUW-QBWMrP848co_SKwR__16cZcc,39359
169
+ matrice/deploy/utils/post_processing/usecases/concrete_crack_detection.py,sha256=s3B_oHfW2FWS1cayh-WYQ5KinRYDjwFwg6F55i9ktjo,39386
170
170
  matrice/deploy/utils/post_processing/usecases/crop_weed_detection.py,sha256=i7BWhC-D7liOg9fzFHFg_upd1fdvXlVHYzDRyHL-AdM,40322
171
171
  matrice/deploy/utils/post_processing/usecases/customer_service.py,sha256=UWS83qxguyAyhh8a0JF5QH9DtKxO8I-gI2BPOjLPxBw,44642
172
172
  matrice/deploy/utils/post_processing/usecases/defect_detection_products.py,sha256=flvTWv6vxa3q4zXD8_e8TW0pqNE5z3LIuvU9ceVKuXg,34481
@@ -176,7 +176,7 @@ matrice/deploy/utils/post_processing/usecases/face_emotion.py,sha256=eRfqBdryB0u
176
176
  matrice/deploy/utils/post_processing/usecases/fashion_detection.py,sha256=f9gpzMDhIW-gyn46k9jgf8nY7YeoqAnTxGOzksabFbE,40457
177
177
  matrice/deploy/utils/post_processing/usecases/field_mapping.py,sha256=JDwYX8pd2W-waDvBh98Y_o_uchJu7wEYbFxOliA4Iq4,39822
178
178
  matrice/deploy/utils/post_processing/usecases/fire_detection.py,sha256=rLaUvU5ygvjGbOmjncEJCl_Oe52SRycS1Ar23LbRssM,32863
179
- matrice/deploy/utils/post_processing/usecases/flare_analysis.py,sha256=90UmC5ji12VvQa1OcQdXZIm9JYN9LOLLjm8JxCREncM,43267
179
+ matrice/deploy/utils/post_processing/usecases/flare_analysis.py,sha256=-egmS3Hs_iGOLeCMfapbkfQ04EWtZx97QRuUcDa-jMU,45340
180
180
  matrice/deploy/utils/post_processing/usecases/flower_segmentation.py,sha256=4I7qMx9Ztxg_hy9KTVX-3qBhAN-QwDt_Yigf9fFjLus,52017
181
181
  matrice/deploy/utils/post_processing/usecases/gender_detection.py,sha256=DEnCTRew6B7DtPcBQVCTtpd_IQMvMusBcu6nadUg2oM,40107
182
182
  matrice/deploy/utils/post_processing/usecases/leaf.py,sha256=cwgB1ZNxkQFtkk-thSJrkXOGou1ghJr1kqtopb3sLD4,37036
@@ -199,11 +199,11 @@ matrice/deploy/utils/post_processing/usecases/skin_cancer_classification_img.py,
199
199
  matrice/deploy/utils/post_processing/usecases/solar_panel.py,sha256=16rECiJLDpIGzBMnlpp4u-_lzAyLUtsx3a3kQzseUYw,38976
200
200
  matrice/deploy/utils/post_processing/usecases/template_usecase.py,sha256=6NC-bTnyB1FeZfdTbQVYK-M5PlAlgdNkWfBDOXCTQ4c,15758
201
201
  matrice/deploy/utils/post_processing/usecases/theft_detection.py,sha256=Rs_zKn2z9YM10fGzTHR44Q3m8TIO1s5UMdiPWA03rbA,28671
202
- matrice/deploy/utils/post_processing/usecases/traffic_sign_monitoring.py,sha256=2Le-j9rAhOYo_hTF4Xj2mI3HAnVTsiYUPhHcab47DMA,32786
202
+ matrice/deploy/utils/post_processing/usecases/traffic_sign_monitoring.py,sha256=nDlEzHgMlUjy_VtJ7usnEzMcdSs-jouqaoJpJ8DYUMw,34351
203
203
  matrice/deploy/utils/post_processing/usecases/underwater_pollution_detection.py,sha256=jqP1ZKfDZe2-56Lyvgb2DxnbqRfvxm6pPL0Ck3esfBk,40356
204
204
  matrice/deploy/utils/post_processing/usecases/vehicle_monitoring.py,sha256=-Q4x0jRYrmbDPAooWbTeYr1TowtvpU5oJ-sVeqRPaM4,31193
205
205
  matrice/deploy/utils/post_processing/usecases/warehouse_object_segmentation.py,sha256=5uZXTJL_A3tUEN08T-_ZQpUoJ9gqbuuMc4z2mT4sMnQ,43753
206
- matrice/deploy/utils/post_processing/usecases/weapon_detection.py,sha256=ait-RCgmu3BH6tNAl9nZgVXO0pSu4ETjtJzN7x6ZFRY,29365
206
+ matrice/deploy/utils/post_processing/usecases/weapon_detection.py,sha256=gea-rjEHmP0hUjpcrcQIHOnhMMHQNqDI90cbpXHnlpI,31071
207
207
  matrice/deploy/utils/post_processing/usecases/weld_defect_detection.py,sha256=b0dAJGKUofbGrwHDJfIYb4pqmvp4Y23JK09Qb-34mxg,30209
208
208
  matrice/deploy/utils/post_processing/usecases/windmill_maintenance.py,sha256=G1eqo3Z-HYmGJ6oeZYrpZwhpvqQ9Lc_T-6S7BLBXHeA,40498
209
209
  matrice/deploy/utils/post_processing/usecases/wound_segmentation.py,sha256=7Nbc7zUQUKdXTSv8XpPuAZLIU3Mr1RU1KyO_D3thoGk,38289
@@ -225,8 +225,8 @@ matrice/deployment/camera_manager.py,sha256=ReBZqm1CNXRImKcbcZ4uWAT3TUWkof1D28oB
225
225
  matrice/deployment/deployment.py,sha256=PLIUD-PxTaC2Zxb3Y12wUddsryV-OJetjCjLoSUh7S4,48103
226
226
  matrice/deployment/inference_pipeline.py,sha256=bXLgd29ViA7o0c7YWLFJl1otBUQfTPb61jS6VawQB0Y,37918
227
227
  matrice/deployment/streaming_gateway_manager.py,sha256=w5swGsuFVfZIdOm2ZuBHRHlRdYYJMLopLsf2gb91lQ8,20946
228
- matrice-1.0.99133.dist-info/licenses/LICENSE.txt,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
229
- matrice-1.0.99133.dist-info/METADATA,sha256=U2B3c3Syax_INlbB91OK6xGPNyge3P2ubrOI4ehIeX0,14624
230
- matrice-1.0.99133.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
231
- matrice-1.0.99133.dist-info/top_level.txt,sha256=P97js8ur6o5ClRqMH3Cjoab_NqbJ6sOQ3rJmVzKBvMc,8
232
- matrice-1.0.99133.dist-info/RECORD,,
228
+ matrice-1.0.99135.dist-info/licenses/LICENSE.txt,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
229
+ matrice-1.0.99135.dist-info/METADATA,sha256=26E4_zThZGeUPboye1ZuJ5GeHG_hI7MrPMN3KTdUMgU,14624
230
+ matrice-1.0.99135.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
231
+ matrice-1.0.99135.dist-info/top_level.txt,sha256=P97js8ur6o5ClRqMH3Cjoab_NqbJ6sOQ3rJmVzKBvMc,8
232
+ matrice-1.0.99135.dist-info/RECORD,,