matrice-analytics 0.1.43__py3-none-any.whl → 0.1.45__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.
Potentially problematic release.
This version of matrice-analytics might be problematic. Click here for more details.
- matrice_analytics/post_processing/config.py +1 -1
- matrice_analytics/post_processing/face_reg/face_recognition.py +145 -99
- matrice_analytics/post_processing/face_reg/face_recognition_client.py +24 -19
- matrice_analytics/post_processing/face_reg/people_activity_logging.py +6 -4
- matrice_analytics/post_processing/ocr/easyocr_extractor.py +3 -1
- matrice_analytics/post_processing/test_cases/test_usecases.py +165 -0
- matrice_analytics/post_processing/usecases/color/clip.py +4 -3
- matrice_analytics/post_processing/usecases/color/color_mapper.py +1 -1
- matrice_analytics/post_processing/usecases/color_detection.py +89 -54
- matrice_analytics/post_processing/usecases/fire_detection.py +89 -55
- matrice_analytics/post_processing/usecases/license_plate_monitoring.py +81 -46
- matrice_analytics/post_processing/usecases/people_counting.py +29 -28
- matrice_analytics/post_processing/usecases/vehicle_monitoring.py +89 -54
- {matrice_analytics-0.1.43.dist-info → matrice_analytics-0.1.45.dist-info}/METADATA +1 -1
- {matrice_analytics-0.1.43.dist-info → matrice_analytics-0.1.45.dist-info}/RECORD +18 -17
- {matrice_analytics-0.1.43.dist-info → matrice_analytics-0.1.45.dist-info}/WHEEL +0 -0
- {matrice_analytics-0.1.43.dist-info → matrice_analytics-0.1.45.dist-info}/licenses/LICENSE.txt +0 -0
- {matrice_analytics-0.1.43.dist-info → matrice_analytics-0.1.45.dist-info}/top_level.txt +0 -0
|
@@ -1566,63 +1566,64 @@ class LicensePlateMonitorUseCase(BaseProcessor):
|
|
|
1566
1566
|
}
|
|
1567
1567
|
return canonical_id
|
|
1568
1568
|
|
|
1569
|
+
def _format_timestamp_for_stream(self, timestamp: float) -> str:
|
|
1570
|
+
"""Format timestamp for streams (YYYY:MM:DD HH:MM:SS format)."""
|
|
1571
|
+
dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
|
|
1572
|
+
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
|
1573
|
+
|
|
1574
|
+
def _format_timestamp_for_video(self, timestamp: float) -> str:
|
|
1575
|
+
"""Format timestamp for video chunks (HH:MM:SS.ms format)."""
|
|
1576
|
+
hours = int(timestamp // 3600)
|
|
1577
|
+
minutes = int((timestamp % 3600) // 60)
|
|
1578
|
+
seconds = round(float(timestamp % 60), 2)
|
|
1579
|
+
return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
|
|
1580
|
+
|
|
1569
1581
|
def _format_timestamp(self, timestamp: Any) -> str:
|
|
1570
|
-
"""Format a timestamp
|
|
1582
|
+
"""Format a timestamp to match the current timestamp format: YYYY:MM:DD HH:MM:SS.
|
|
1571
1583
|
|
|
1572
1584
|
The input can be either:
|
|
1573
|
-
1. A numeric Unix timestamp (``float`` / ``int``)
|
|
1574
|
-
|
|
1575
|
-
2. A string already following the same layout.
|
|
1585
|
+
1. A numeric Unix timestamp (``float`` / ``int``) – it will be converted to datetime.
|
|
1586
|
+
2. A string in the format ``YYYY-MM-DD-HH:MM:SS.ffffff UTC``.
|
|
1576
1587
|
|
|
1577
|
-
The returned value
|
|
1578
|
-
the fractional seconds portion to **exactly two digits**.
|
|
1588
|
+
The returned value will be in the format: YYYY:MM:DD HH:MM:SS (no milliseconds, no UTC suffix).
|
|
1579
1589
|
|
|
1580
1590
|
Example
|
|
1581
1591
|
-------
|
|
1582
|
-
>>> self._format_timestamp("2025-
|
|
1583
|
-
'2025
|
|
1592
|
+
>>> self._format_timestamp("2025-10-27-19:31:20.187574 UTC")
|
|
1593
|
+
'2025:10:27 19:31:20'
|
|
1584
1594
|
"""
|
|
1585
1595
|
|
|
1586
|
-
# Convert numeric timestamps to
|
|
1596
|
+
# Convert numeric timestamps to datetime first
|
|
1587
1597
|
if isinstance(timestamp, (int, float)):
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
)
|
|
1598
|
+
dt = datetime.fromtimestamp(timestamp, timezone.utc)
|
|
1599
|
+
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
|
1591
1600
|
|
|
1592
1601
|
# Ensure we are working with a string from here on
|
|
1593
1602
|
if not isinstance(timestamp, str):
|
|
1594
1603
|
return str(timestamp)
|
|
1595
1604
|
|
|
1596
|
-
#
|
|
1597
|
-
|
|
1598
|
-
return timestamp
|
|
1599
|
-
|
|
1600
|
-
# Split out the main portion (up to the decimal point)
|
|
1601
|
-
main_part, fractional_and_suffix = timestamp.split('.', 1)
|
|
1602
|
-
|
|
1603
|
-
# Separate fractional digits from the suffix (typically ' UTC')
|
|
1604
|
-
if ' ' in fractional_and_suffix:
|
|
1605
|
-
fractional_part, suffix = fractional_and_suffix.split(' ', 1)
|
|
1606
|
-
suffix = ' ' + suffix # Re-attach the space removed by split
|
|
1607
|
-
else:
|
|
1608
|
-
fractional_part, suffix = fractional_and_suffix, ''
|
|
1609
|
-
|
|
1610
|
-
# Guarantee exactly two digits for the fractional part
|
|
1611
|
-
fractional_part = (fractional_part + '00')[:2]
|
|
1605
|
+
# Remove ' UTC' suffix if present
|
|
1606
|
+
timestamp_clean = timestamp.replace(' UTC', '').strip()
|
|
1612
1607
|
|
|
1613
|
-
|
|
1608
|
+
# Remove milliseconds if present (everything after the last dot)
|
|
1609
|
+
if '.' in timestamp_clean:
|
|
1610
|
+
timestamp_clean = timestamp_clean.split('.')[0]
|
|
1614
1611
|
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1612
|
+
# Parse the timestamp string and convert to desired format
|
|
1613
|
+
try:
|
|
1614
|
+
# Handle format: YYYY-MM-DD-HH:MM:SS
|
|
1615
|
+
if timestamp_clean.count('-') >= 2:
|
|
1616
|
+
# Replace first two dashes with colons for date part, third with space
|
|
1617
|
+
parts = timestamp_clean.split('-')
|
|
1618
|
+
if len(parts) >= 4:
|
|
1619
|
+
# parts = ['2025', '10', '27', '19:31:20']
|
|
1620
|
+
formatted = f"{parts[0]}:{parts[1]}:{parts[2]} {'-'.join(parts[3:])}"
|
|
1621
|
+
return formatted
|
|
1622
|
+
except Exception:
|
|
1623
|
+
pass
|
|
1624
|
+
|
|
1625
|
+
# If parsing fails, return the cleaned string as-is
|
|
1626
|
+
return timestamp_clean
|
|
1626
1627
|
|
|
1627
1628
|
def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
|
|
1628
1629
|
"""Get formatted current timestamp based on stream type."""
|
|
@@ -1671,23 +1672,57 @@ class LicensePlateMonitorUseCase(BaseProcessor):
|
|
|
1671
1672
|
|
|
1672
1673
|
if precision:
|
|
1673
1674
|
if self.start_timer is None:
|
|
1674
|
-
|
|
1675
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
1676
|
+
if not candidate or candidate == "NA":
|
|
1677
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1678
|
+
self.start_timer = candidate
|
|
1675
1679
|
return self._format_timestamp(self.start_timer)
|
|
1676
1680
|
elif stream_info.get("input_settings", {}).get("start_frame", "na") == 1:
|
|
1677
|
-
|
|
1681
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
1682
|
+
if not candidate or candidate == "NA":
|
|
1683
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1684
|
+
self.start_timer = candidate
|
|
1678
1685
|
return self._format_timestamp(self.start_timer)
|
|
1679
1686
|
else:
|
|
1680
1687
|
return self._format_timestamp(self.start_timer)
|
|
1681
1688
|
|
|
1682
1689
|
if self.start_timer is None:
|
|
1683
|
-
|
|
1690
|
+
# Prefer direct input_settings.stream_time if available and not NA
|
|
1691
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
1692
|
+
if not candidate or candidate == "NA":
|
|
1693
|
+
# Fallback to nested stream_info.stream_time used by current timestamp path
|
|
1694
|
+
stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
|
|
1695
|
+
if stream_time_str:
|
|
1696
|
+
try:
|
|
1697
|
+
timestamp_str = stream_time_str.replace(" UTC", "")
|
|
1698
|
+
dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
|
|
1699
|
+
self._tracking_start_time = dt.replace(tzinfo=timezone.utc).timestamp()
|
|
1700
|
+
candidate = datetime.fromtimestamp(self._tracking_start_time, timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1701
|
+
except:
|
|
1702
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1703
|
+
else:
|
|
1704
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1705
|
+
self.start_timer = candidate
|
|
1684
1706
|
return self._format_timestamp(self.start_timer)
|
|
1685
1707
|
elif stream_info.get("input_settings", {}).get("start_frame", "na") == 1:
|
|
1686
|
-
|
|
1708
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
1709
|
+
if not candidate or candidate == "NA":
|
|
1710
|
+
stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
|
|
1711
|
+
if stream_time_str:
|
|
1712
|
+
try:
|
|
1713
|
+
timestamp_str = stream_time_str.replace(" UTC", "")
|
|
1714
|
+
dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
|
|
1715
|
+
ts = dt.replace(tzinfo=timezone.utc).timestamp()
|
|
1716
|
+
candidate = datetime.fromtimestamp(ts, timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1717
|
+
except:
|
|
1718
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1719
|
+
else:
|
|
1720
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
1721
|
+
self.start_timer = candidate
|
|
1687
1722
|
return self._format_timestamp(self.start_timer)
|
|
1688
1723
|
|
|
1689
1724
|
else:
|
|
1690
|
-
if self.start_timer is not None:
|
|
1725
|
+
if self.start_timer is not None and self.start_timer != "NA":
|
|
1691
1726
|
return self._format_timestamp(self.start_timer)
|
|
1692
1727
|
|
|
1693
1728
|
if self._tracking_start_time is None:
|
|
@@ -1705,7 +1740,7 @@ class LicensePlateMonitorUseCase(BaseProcessor):
|
|
|
1705
1740
|
dt = datetime.fromtimestamp(self._tracking_start_time, tz=timezone.utc)
|
|
1706
1741
|
dt = dt.replace(minute=0, second=0, microsecond=0)
|
|
1707
1742
|
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
|
1708
|
-
|
|
1743
|
+
|
|
1709
1744
|
def _get_tracking_start_time(self) -> str:
|
|
1710
1745
|
"""Get the tracking start time, formatted as a string."""
|
|
1711
1746
|
if self._tracking_start_time is None:
|
|
@@ -437,50 +437,51 @@ class PeopleCountingUseCase(BaseProcessor):
|
|
|
437
437
|
return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
|
|
438
438
|
|
|
439
439
|
def _format_timestamp(self, timestamp: Any) -> str:
|
|
440
|
-
"""Format a timestamp
|
|
440
|
+
"""Format a timestamp to match the current timestamp format: YYYY:MM:DD HH:MM:SS.
|
|
441
441
|
|
|
442
442
|
The input can be either:
|
|
443
|
-
1. A numeric Unix timestamp (``float`` / ``int``) – it will
|
|
444
|
-
|
|
445
|
-
2. A string already following the same layout.
|
|
443
|
+
1. A numeric Unix timestamp (``float`` / ``int``) – it will be converted to datetime.
|
|
444
|
+
2. A string in the format ``YYYY-MM-DD-HH:MM:SS.ffffff UTC``.
|
|
446
445
|
|
|
447
|
-
The returned value
|
|
448
|
-
the fractional seconds portion to **exactly two digits**.
|
|
446
|
+
The returned value will be in the format: YYYY:MM:DD HH:MM:SS (no milliseconds, no UTC suffix).
|
|
449
447
|
|
|
450
448
|
Example
|
|
451
449
|
-------
|
|
452
|
-
>>> self._format_timestamp("2025-
|
|
453
|
-
'2025
|
|
450
|
+
>>> self._format_timestamp("2025-10-27-19:31:20.187574 UTC")
|
|
451
|
+
'2025:10:27 19:31:20'
|
|
454
452
|
"""
|
|
455
453
|
|
|
456
|
-
# Convert numeric timestamps to
|
|
454
|
+
# Convert numeric timestamps to datetime first
|
|
457
455
|
if isinstance(timestamp, (int, float)):
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
)
|
|
456
|
+
dt = datetime.fromtimestamp(timestamp, timezone.utc)
|
|
457
|
+
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
|
461
458
|
|
|
462
459
|
# Ensure we are working with a string from here on
|
|
463
460
|
if not isinstance(timestamp, str):
|
|
464
461
|
return str(timestamp)
|
|
465
462
|
|
|
466
|
-
#
|
|
467
|
-
|
|
468
|
-
return timestamp
|
|
469
|
-
|
|
470
|
-
# Split out the main portion (up to the decimal point)
|
|
471
|
-
main_part, fractional_and_suffix = timestamp.split('.', 1)
|
|
463
|
+
# Remove ' UTC' suffix if present
|
|
464
|
+
timestamp_clean = timestamp.replace(' UTC', '').strip()
|
|
472
465
|
|
|
473
|
-
#
|
|
474
|
-
if '
|
|
475
|
-
|
|
476
|
-
suffix = ' ' + suffix # Re-attach the space removed by split
|
|
477
|
-
else:
|
|
478
|
-
fractional_part, suffix = fractional_and_suffix, ''
|
|
479
|
-
|
|
480
|
-
# Guarantee exactly two digits for the fractional part
|
|
481
|
-
fractional_part = (fractional_part + '00')[:2]
|
|
466
|
+
# Remove milliseconds if present (everything after the last dot)
|
|
467
|
+
if '.' in timestamp_clean:
|
|
468
|
+
timestamp_clean = timestamp_clean.split('.')[0]
|
|
482
469
|
|
|
483
|
-
|
|
470
|
+
# Parse the timestamp string and convert to desired format
|
|
471
|
+
try:
|
|
472
|
+
# Handle format: YYYY-MM-DD-HH:MM:SS
|
|
473
|
+
if timestamp_clean.count('-') >= 2:
|
|
474
|
+
# Replace first two dashes with colons for date part, third with space
|
|
475
|
+
parts = timestamp_clean.split('-')
|
|
476
|
+
if len(parts) >= 4:
|
|
477
|
+
# parts = ['2025', '10', '27', '19:31:20']
|
|
478
|
+
formatted = f"{parts[0]}:{parts[1]}:{parts[2]} {'-'.join(parts[3:])}"
|
|
479
|
+
return formatted
|
|
480
|
+
except Exception:
|
|
481
|
+
pass
|
|
482
|
+
|
|
483
|
+
# If parsing fails, return the cleaned string as-is
|
|
484
|
+
return timestamp_clean
|
|
484
485
|
|
|
485
486
|
def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
|
|
486
487
|
"""Get formatted current timestamp based on stream type."""
|
|
@@ -759,11 +759,58 @@ class VehicleMonitoringUseCase(BaseProcessor):
|
|
|
759
759
|
seconds = round(float(timestamp % 60), 2)
|
|
760
760
|
return f"{hours:02d}:{minutes:02d}:{seconds:.1f}"
|
|
761
761
|
|
|
762
|
+
def _format_timestamp(self, timestamp: Any) -> str:
|
|
763
|
+
"""Format a timestamp to match the current timestamp format: YYYY:MM:DD HH:MM:SS.
|
|
764
|
+
|
|
765
|
+
The input can be either:
|
|
766
|
+
1. A numeric Unix timestamp (``float`` / ``int``) – it will be converted to datetime.
|
|
767
|
+
2. A string in the format ``YYYY-MM-DD-HH:MM:SS.ffffff UTC``.
|
|
768
|
+
|
|
769
|
+
The returned value will be in the format: YYYY:MM:DD HH:MM:SS (no milliseconds, no UTC suffix).
|
|
770
|
+
|
|
771
|
+
Example
|
|
772
|
+
-------
|
|
773
|
+
>>> self._format_timestamp("2025-10-27-19:31:20.187574 UTC")
|
|
774
|
+
'2025:10:27 19:31:20'
|
|
775
|
+
"""
|
|
776
|
+
|
|
777
|
+
# Convert numeric timestamps to datetime first
|
|
778
|
+
if isinstance(timestamp, (int, float)):
|
|
779
|
+
dt = datetime.fromtimestamp(timestamp, timezone.utc)
|
|
780
|
+
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
|
781
|
+
|
|
782
|
+
# Ensure we are working with a string from here on
|
|
783
|
+
if not isinstance(timestamp, str):
|
|
784
|
+
return str(timestamp)
|
|
785
|
+
|
|
786
|
+
# Remove ' UTC' suffix if present
|
|
787
|
+
timestamp_clean = timestamp.replace(' UTC', '').strip()
|
|
788
|
+
|
|
789
|
+
# Remove milliseconds if present (everything after the last dot)
|
|
790
|
+
if '.' in timestamp_clean:
|
|
791
|
+
timestamp_clean = timestamp_clean.split('.')[0]
|
|
792
|
+
|
|
793
|
+
# Parse the timestamp string and convert to desired format
|
|
794
|
+
try:
|
|
795
|
+
# Handle format: YYYY-MM-DD-HH:MM:SS
|
|
796
|
+
if timestamp_clean.count('-') >= 2:
|
|
797
|
+
# Replace first two dashes with colons for date part, third with space
|
|
798
|
+
parts = timestamp_clean.split('-')
|
|
799
|
+
if len(parts) >= 4:
|
|
800
|
+
# parts = ['2025', '10', '27', '19:31:20']
|
|
801
|
+
formatted = f"{parts[0]}:{parts[1]}:{parts[2]} {'-'.join(parts[3:])}"
|
|
802
|
+
return formatted
|
|
803
|
+
except Exception:
|
|
804
|
+
pass
|
|
805
|
+
|
|
806
|
+
# If parsing fails, return the cleaned string as-is
|
|
807
|
+
return timestamp_clean
|
|
808
|
+
|
|
762
809
|
def _get_current_timestamp_str(self, stream_info: Optional[Dict[str, Any]], precision=False, frame_id: Optional[str]=None) -> str:
|
|
763
810
|
"""Get formatted current timestamp based on stream type."""
|
|
811
|
+
|
|
764
812
|
if not stream_info:
|
|
765
813
|
return "00:00:00.00"
|
|
766
|
-
|
|
767
814
|
if precision:
|
|
768
815
|
if stream_info.get("input_settings", {}).get("start_frame", "na") != "na":
|
|
769
816
|
if frame_id:
|
|
@@ -772,7 +819,6 @@ class VehicleMonitoringUseCase(BaseProcessor):
|
|
|
772
819
|
start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
|
|
773
820
|
stream_time_str = self._format_timestamp_for_video(start_time)
|
|
774
821
|
|
|
775
|
-
|
|
776
822
|
return self._format_timestamp(stream_info.get("input_settings", {}).get("stream_time", "NA"))
|
|
777
823
|
else:
|
|
778
824
|
return datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
@@ -784,7 +830,8 @@ class VehicleMonitoringUseCase(BaseProcessor):
|
|
|
784
830
|
start_time = stream_info.get("input_settings", {}).get("start_frame", 30)/stream_info.get("input_settings", {}).get("original_fps", 30)
|
|
785
831
|
|
|
786
832
|
stream_time_str = self._format_timestamp_for_video(start_time)
|
|
787
|
-
|
|
833
|
+
|
|
834
|
+
|
|
788
835
|
return self._format_timestamp(stream_info.get("input_settings", {}).get("stream_time", "NA"))
|
|
789
836
|
else:
|
|
790
837
|
stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
|
|
@@ -806,23 +853,57 @@ class VehicleMonitoringUseCase(BaseProcessor):
|
|
|
806
853
|
|
|
807
854
|
if precision:
|
|
808
855
|
if self.start_timer is None:
|
|
809
|
-
|
|
856
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
857
|
+
if not candidate or candidate == "NA":
|
|
858
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
859
|
+
self.start_timer = candidate
|
|
810
860
|
return self._format_timestamp(self.start_timer)
|
|
811
861
|
elif stream_info.get("input_settings", {}).get("start_frame", "na") == 1:
|
|
812
|
-
|
|
862
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
863
|
+
if not candidate or candidate == "NA":
|
|
864
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
865
|
+
self.start_timer = candidate
|
|
813
866
|
return self._format_timestamp(self.start_timer)
|
|
814
867
|
else:
|
|
815
868
|
return self._format_timestamp(self.start_timer)
|
|
816
869
|
|
|
817
870
|
if self.start_timer is None:
|
|
818
|
-
|
|
871
|
+
# Prefer direct input_settings.stream_time if available and not NA
|
|
872
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
873
|
+
if not candidate or candidate == "NA":
|
|
874
|
+
# Fallback to nested stream_info.stream_time used by current timestamp path
|
|
875
|
+
stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
|
|
876
|
+
if stream_time_str:
|
|
877
|
+
try:
|
|
878
|
+
timestamp_str = stream_time_str.replace(" UTC", "")
|
|
879
|
+
dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
|
|
880
|
+
self._tracking_start_time = dt.replace(tzinfo=timezone.utc).timestamp()
|
|
881
|
+
candidate = datetime.fromtimestamp(self._tracking_start_time, timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
882
|
+
except:
|
|
883
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
884
|
+
else:
|
|
885
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
886
|
+
self.start_timer = candidate
|
|
819
887
|
return self._format_timestamp(self.start_timer)
|
|
820
888
|
elif stream_info.get("input_settings", {}).get("start_frame", "na") == 1:
|
|
821
|
-
|
|
889
|
+
candidate = stream_info.get("input_settings", {}).get("stream_time")
|
|
890
|
+
if not candidate or candidate == "NA":
|
|
891
|
+
stream_time_str = stream_info.get("input_settings", {}).get("stream_info", {}).get("stream_time", "")
|
|
892
|
+
if stream_time_str:
|
|
893
|
+
try:
|
|
894
|
+
timestamp_str = stream_time_str.replace(" UTC", "")
|
|
895
|
+
dt = datetime.strptime(timestamp_str, "%Y-%m-%d-%H:%M:%S.%f")
|
|
896
|
+
ts = dt.replace(tzinfo=timezone.utc).timestamp()
|
|
897
|
+
candidate = datetime.fromtimestamp(ts, timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
898
|
+
except:
|
|
899
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
900
|
+
else:
|
|
901
|
+
candidate = datetime.now(timezone.utc).strftime("%Y-%m-%d-%H:%M:%S.%f UTC")
|
|
902
|
+
self.start_timer = candidate
|
|
822
903
|
return self._format_timestamp(self.start_timer)
|
|
823
904
|
|
|
824
905
|
else:
|
|
825
|
-
if self.start_timer is not None:
|
|
906
|
+
if self.start_timer is not None and self.start_timer != "NA":
|
|
826
907
|
return self._format_timestamp(self.start_timer)
|
|
827
908
|
|
|
828
909
|
if self._tracking_start_time is None:
|
|
@@ -841,52 +922,6 @@ class VehicleMonitoringUseCase(BaseProcessor):
|
|
|
841
922
|
dt = dt.replace(minute=0, second=0, microsecond=0)
|
|
842
923
|
return dt.strftime('%Y:%m:%d %H:%M:%S')
|
|
843
924
|
|
|
844
|
-
def _format_timestamp(self, timestamp: Any) -> str:
|
|
845
|
-
"""Format a timestamp so that exactly two digits follow the decimal point (milliseconds).
|
|
846
|
-
|
|
847
|
-
The input can be either:
|
|
848
|
-
1. A numeric Unix timestamp (``float`` / ``int``) – it will first be converted to a
|
|
849
|
-
string in the format ``YYYY-MM-DD-HH:MM:SS.ffffff UTC``.
|
|
850
|
-
2. A string already following the same layout.
|
|
851
|
-
|
|
852
|
-
The returned value preserves the overall format of the input but truncates or pads
|
|
853
|
-
the fractional seconds portion to **exactly two digits**.
|
|
854
|
-
|
|
855
|
-
Example
|
|
856
|
-
-------
|
|
857
|
-
>>> self._format_timestamp("2025-08-19-04:22:47.187574 UTC")
|
|
858
|
-
'2025-08-19-04:22:47.18 UTC'
|
|
859
|
-
"""
|
|
860
|
-
|
|
861
|
-
# Convert numeric timestamps to the expected string representation first
|
|
862
|
-
if isinstance(timestamp, (int, float)):
|
|
863
|
-
timestamp = datetime.fromtimestamp(timestamp, timezone.utc).strftime(
|
|
864
|
-
'%Y-%m-%d-%H:%M:%S.%f UTC'
|
|
865
|
-
)
|
|
866
|
-
|
|
867
|
-
# Ensure we are working with a string from here on
|
|
868
|
-
if not isinstance(timestamp, str):
|
|
869
|
-
return str(timestamp)
|
|
870
|
-
|
|
871
|
-
# If there is no fractional component, simply return the original string
|
|
872
|
-
if '.' not in timestamp:
|
|
873
|
-
return timestamp
|
|
874
|
-
|
|
875
|
-
# Split out the main portion (up to the decimal point)
|
|
876
|
-
main_part, fractional_and_suffix = timestamp.split('.', 1)
|
|
877
|
-
|
|
878
|
-
# Separate fractional digits from the suffix (typically ' UTC')
|
|
879
|
-
if ' ' in fractional_and_suffix:
|
|
880
|
-
fractional_part, suffix = fractional_and_suffix.split(' ', 1)
|
|
881
|
-
suffix = ' ' + suffix # Re-attach the space removed by split
|
|
882
|
-
else:
|
|
883
|
-
fractional_part, suffix = fractional_and_suffix, ''
|
|
884
|
-
|
|
885
|
-
# Guarantee exactly two digits for the fractional part
|
|
886
|
-
fractional_part = (fractional_part + '00')[:2]
|
|
887
|
-
|
|
888
|
-
return f"{main_part}.{fractional_part}{suffix}"
|
|
889
|
-
|
|
890
925
|
def _count_categories(self, detections: list, config: VehicleMonitoringConfig) -> dict:
|
|
891
926
|
counts = {}
|
|
892
927
|
for det in detections:
|
|
@@ -12,7 +12,7 @@ matrice_analytics/boundary_drawing_internal/usage/boundary_drawer_launcher.py,sh
|
|
|
12
12
|
matrice_analytics/boundary_drawing_internal/usage/simple_boundary_launcher.py,sha256=jHPriRLorLuiC8km0MFNS96w121tKxd7t5GQl7I5kKE,3494
|
|
13
13
|
matrice_analytics/post_processing/README.md,sha256=bDszazvqV5xbGhMM6hDaMctIyk5gox9bADo2IZZ9Goo,13368
|
|
14
14
|
matrice_analytics/post_processing/__init__.py,sha256=dxGBUQaRCGndQmXpYAWqUhDeUZAcxU-_6HFnm3GRDRA,29417
|
|
15
|
-
matrice_analytics/post_processing/config.py,sha256=
|
|
15
|
+
matrice_analytics/post_processing/config.py,sha256=XQLl1bW3X0vqb--b_OAQcvSP0JKPGEcLUdHE8NRnqVs,6770
|
|
16
16
|
matrice_analytics/post_processing/post_processor.py,sha256=F838_vc7p9tjcp-vTMgTbpHqQcLX94xhL9HM06Wvpo8,44384
|
|
17
17
|
matrice_analytics/post_processing/advanced_tracker/README.md,sha256=RM8dynVoUWKn_hTbw9c6jHAbnQj-8hEAXnmuRZr2w1M,22485
|
|
18
18
|
matrice_analytics/post_processing/advanced_tracker/__init__.py,sha256=tAPFzI_Yep5TLX60FDwKqBqppc-EbxSr0wNsQ9DGI1o,423
|
|
@@ -29,11 +29,11 @@ matrice_analytics/post_processing/core/config_utils.py,sha256=QuAS-_JKSoNOtfUWgr
|
|
|
29
29
|
matrice_analytics/post_processing/face_reg/__init__.py,sha256=yntaiGlW9vdjBpPZQXNuovALihJPzRlFyUE88l3MhBA,1364
|
|
30
30
|
matrice_analytics/post_processing/face_reg/compare_similarity.py,sha256=NlFc8b2a74k0PqSFAbuM_fUbA1BT3pr3VUgvSqRpJzQ,23396
|
|
31
31
|
matrice_analytics/post_processing/face_reg/embedding_manager.py,sha256=qbh0df3-YbE0qvFDQvjpCg-JrsCZRJ5capjQ2LPOj1k,35619
|
|
32
|
-
matrice_analytics/post_processing/face_reg/face_recognition.py,sha256=
|
|
33
|
-
matrice_analytics/post_processing/face_reg/face_recognition_client.py,sha256=
|
|
34
|
-
matrice_analytics/post_processing/face_reg/people_activity_logging.py,sha256=
|
|
32
|
+
matrice_analytics/post_processing/face_reg/face_recognition.py,sha256=iKblqR88bcvP6Vu-8_FEuBLgGSZs5nfJVSTY-U4Ws9c,92786
|
|
33
|
+
matrice_analytics/post_processing/face_reg/face_recognition_client.py,sha256=4H0I1fLmv6BaqWQXRWOHN12GIV5IsHk5xkDOUI-JGQ8,28242
|
|
34
|
+
matrice_analytics/post_processing/face_reg/people_activity_logging.py,sha256=xV5BliZf4As_sg4h-fqav5-KZeGi96fEfv8vLSliEk8,13835
|
|
35
35
|
matrice_analytics/post_processing/ocr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
-
matrice_analytics/post_processing/ocr/easyocr_extractor.py,sha256=
|
|
36
|
+
matrice_analytics/post_processing/ocr/easyocr_extractor.py,sha256=RMrRoGb2gMcJEGouQn8U9cCgCLXPT7qRa8liI4LNxFM,11555
|
|
37
37
|
matrice_analytics/post_processing/ocr/postprocessing.py,sha256=RILArp8I9WRH7bALVZ9wPGc-aR7YMdqV1ndOOIcOnGQ,12309
|
|
38
38
|
matrice_analytics/post_processing/ocr/preprocessing.py,sha256=LZolyUw4syMU6Q0V6SQzvkITVSmlkvwu0p9cUNhkbgA,1790
|
|
39
39
|
matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/__init__.py,sha256=OHd4VO0dI8daHojE5900DvreiDT6SGOSZF6VvxU0Tx4,184
|
|
@@ -80,6 +80,7 @@ matrice_analytics/post_processing/test_cases/test_customer_service.py,sha256=gfJ
|
|
|
80
80
|
matrice_analytics/post_processing/test_cases/test_data_generators.py,sha256=RYeY1pCQdPSAsnevdMkqudBOCIDBrWS2-cZK-hcOSlU,20214
|
|
81
81
|
matrice_analytics/post_processing/test_cases/test_people_counting.py,sha256=1QINfIvtQ5idIMHaojgilRcSiCCVqZPd1fyGOM08HiE,19194
|
|
82
82
|
matrice_analytics/post_processing/test_cases/test_processor.py,sha256=Mi0dRkpszChMS1SOPVBHj2bgkRt93Xxl94mvpQ-5yws,19799
|
|
83
|
+
matrice_analytics/post_processing/test_cases/test_usecases.py,sha256=e09c9JaOhtiwO5_TXDV5V_dPsc_jJBG36egu-WM02mE,6331
|
|
83
84
|
matrice_analytics/post_processing/test_cases/test_utilities.py,sha256=zUtBqwELjovkhQfhn1vM-y7aH04z9sFvt6LIpXXBFSE,13415
|
|
84
85
|
matrice_analytics/post_processing/test_cases/test_utils.py,sha256=lgDX0vILylA6m8sG3_3kxAJ7TiDo8xkprJNfBrLoID4,29371
|
|
85
86
|
matrice_analytics/post_processing/usecases/Histopathological_Cancer_Detection_img.py,sha256=bHDXxxG3QgWMFZbDuBaJWpkIvxTXsFMTqCPBCFm3SDs,30247
|
|
@@ -100,7 +101,7 @@ matrice_analytics/post_processing/usecases/cardiomegaly_classification.py,sha256
|
|
|
100
101
|
matrice_analytics/post_processing/usecases/cell_microscopy_segmentation.py,sha256=eQ_s5u3Vnvja6-FmI6ZPxlNkaZtG-pVjTu8NuLjZJ5M,43714
|
|
101
102
|
matrice_analytics/post_processing/usecases/chicken_pose_detection.py,sha256=-e8di7Am-E-FCQFrSY8qJTO1aWtdRAVJoE-VKBgcyyI,29291
|
|
102
103
|
matrice_analytics/post_processing/usecases/child_monitoring.py,sha256=z3oymoqq4hDGwA8MkdEONZW_Vx5CAZmvzZaNLsqmCfw,39380
|
|
103
|
-
matrice_analytics/post_processing/usecases/color_detection.py,sha256=
|
|
104
|
+
matrice_analytics/post_processing/usecases/color_detection.py,sha256=56oLhecGN8jaPcRLNpZ-AJYjhYqvcRq_BX7rjkPHW0s,92361
|
|
104
105
|
matrice_analytics/post_processing/usecases/color_map_utils.py,sha256=SP-AEVcjLmL8rxblu-ixqUJC2fqlcr7ab4hWo4Fcr_k,2677
|
|
105
106
|
matrice_analytics/post_processing/usecases/concrete_crack_detection.py,sha256=pxhOH_hG4hq9yytNepbGMdk2W_lTG8D1_2RAagaPBkg,40252
|
|
106
107
|
matrice_analytics/post_processing/usecases/crop_weed_detection.py,sha256=Ao1k5fJDYU_f6yZ8VO-jW8-esECV0-zY5Q570c_fako,35674
|
|
@@ -115,7 +116,7 @@ matrice_analytics/post_processing/usecases/face_emotion.py,sha256=eRfqBdryB0uNoO
|
|
|
115
116
|
matrice_analytics/post_processing/usecases/face_recognition.py,sha256=T5xAuv6b9OrkmTmoXgZs4LZ5XUsbvp9xCpeLBwdu7eI,40231
|
|
116
117
|
matrice_analytics/post_processing/usecases/fashion_detection.py,sha256=f9gpzMDhIW-gyn46k9jgf8nY7YeoqAnTxGOzksabFbE,40457
|
|
117
118
|
matrice_analytics/post_processing/usecases/field_mapping.py,sha256=JDwYX8pd2W-waDvBh98Y_o_uchJu7wEYbFxOliA4Iq4,39822
|
|
118
|
-
matrice_analytics/post_processing/usecases/fire_detection.py,sha256=
|
|
119
|
+
matrice_analytics/post_processing/usecases/fire_detection.py,sha256=o57jhIrsVBRkpD4nzaUHyuBRA4YZb3yNvQz0Ri_xiVg,54613
|
|
119
120
|
matrice_analytics/post_processing/usecases/flare_analysis.py,sha256=3nf4fUeUwlP_UII0h5fQkUGPXbr32ZnJjaM-dukNSP8,42680
|
|
120
121
|
matrice_analytics/post_processing/usecases/flower_segmentation.py,sha256=4I7qMx9Ztxg_hy9KTVX-3qBhAN-QwDt_Yigf9fFjLus,52017
|
|
121
122
|
matrice_analytics/post_processing/usecases/gas_leak_detection.py,sha256=KL2ft7fXvjTas-65-QgcJm3W8KBsrwF44qibSXjfaLc,40557
|
|
@@ -126,7 +127,7 @@ matrice_analytics/post_processing/usecases/leaf.py,sha256=cwgB1ZNxkQFtkk-thSJrkX
|
|
|
126
127
|
matrice_analytics/post_processing/usecases/leaf_disease.py,sha256=bkiLccTdf4KUq3he4eCpBlKXb5exr-WBhQ_oWQ7os68,36225
|
|
127
128
|
matrice_analytics/post_processing/usecases/leak_detection.py,sha256=oOCLLVMuXVeXPHyN8FUrD3U9JYJJwIz-5fcEMgvLdls,40531
|
|
128
129
|
matrice_analytics/post_processing/usecases/license_plate_detection.py,sha256=dsavd92-wnyXCNrCzaRj24zH7BVvLSa09HkYsrOXYDM,50806
|
|
129
|
-
matrice_analytics/post_processing/usecases/license_plate_monitoring.py,sha256=
|
|
130
|
+
matrice_analytics/post_processing/usecases/license_plate_monitoring.py,sha256=hjc9tQkUzVwvWuNohw28P2SJNHb25P5ERZbNlRkSKOk,91379
|
|
130
131
|
matrice_analytics/post_processing/usecases/litter_monitoring.py,sha256=XaHAUGRBDJg_iVbu8hRMjTR-5TqrLj6ZNCRkInbzZTY,33255
|
|
131
132
|
matrice_analytics/post_processing/usecases/mask_detection.py,sha256=L_s6ZiT5zeXG-BsFcskb3HEG98DhLgqeMSDmCuwOteU,41501
|
|
132
133
|
matrice_analytics/post_processing/usecases/natural_disaster.py,sha256=ehxdPBoYcZWGVDOVn_mHFoz4lIE8LrveAkuXQj0n9XE,44253
|
|
@@ -134,7 +135,7 @@ matrice_analytics/post_processing/usecases/parking.py,sha256=lqTGqcjUZZPFw3tu11H
|
|
|
134
135
|
matrice_analytics/post_processing/usecases/parking_space_detection.py,sha256=xwhkJjGGKcT827URbasi3olYqhd95Sh0zsEIphwzcgY,39561
|
|
135
136
|
matrice_analytics/post_processing/usecases/pcb_defect_detection.py,sha256=xH3q-WoR3TwMUeUvWw1W7vPLdCUfu_Kl_gQ9dZFf1SE,43006
|
|
136
137
|
matrice_analytics/post_processing/usecases/pedestrian_detection.py,sha256=hPFtvpWXXEsbDavmuiXIhrosMNlOhGya--jukT-ZOHA,39288
|
|
137
|
-
matrice_analytics/post_processing/usecases/people_counting.py,sha256=
|
|
138
|
+
matrice_analytics/post_processing/usecases/people_counting.py,sha256=mlzezqESW2qifW2PmsygWMjHLw6v8I34p9L2RwbxZMo,35267
|
|
138
139
|
matrice_analytics/post_processing/usecases/people_counting_bckp.py,sha256=WM9te7oYyhu5f_bIMye_D5BpEn6CwA-6Kz95IMLmSbs,82209
|
|
139
140
|
matrice_analytics/post_processing/usecases/people_tracking.py,sha256=iXzGJgqKgWxvIVLqa1cFKkiF0DrHolwghSiJ2P8mDhc,90484
|
|
140
141
|
matrice_analytics/post_processing/usecases/pipeline_detection.py,sha256=VsLTXMAqx0tRw7Olrxqx7SBLolZR7p2aFOrdSXLS-kE,30796
|
|
@@ -158,7 +159,7 @@ matrice_analytics/post_processing/usecases/theft_detection.py,sha256=Rs_zKn2z9YM
|
|
|
158
159
|
matrice_analytics/post_processing/usecases/traffic_sign_monitoring.py,sha256=nDlEzHgMlUjy_VtJ7usnEzMcdSs-jouqaoJpJ8DYUMw,34351
|
|
159
160
|
matrice_analytics/post_processing/usecases/underground_pipeline_defect_detection.py,sha256=W_2joZStsP0jl2zn89-jtdtqqGv3vJ0amsalbE5WKwo,37647
|
|
160
161
|
matrice_analytics/post_processing/usecases/underwater_pollution_detection.py,sha256=jqP1ZKfDZe2-56Lyvgb2DxnbqRfvxm6pPL0Ck3esfBk,40356
|
|
161
|
-
matrice_analytics/post_processing/usecases/vehicle_monitoring.py,sha256=
|
|
162
|
+
matrice_analytics/post_processing/usecases/vehicle_monitoring.py,sha256=QsO-coozfy29rY6NszwA6A7nFBOGysfMz5S5VVY7Beg,52849
|
|
162
163
|
matrice_analytics/post_processing/usecases/warehouse_object_segmentation.py,sha256=5uZXTJL_A3tUEN08T-_ZQpUoJ9gqbuuMc4z2mT4sMnQ,43753
|
|
163
164
|
matrice_analytics/post_processing/usecases/waterbody_segmentation.py,sha256=JsCxDEMB8s4WDcezfJDr2zrjM-TCjB9hxOztzSvWmpY,45268
|
|
164
165
|
matrice_analytics/post_processing/usecases/weapon_detection.py,sha256=AhbVpJaa2I3aRCEAdIxovY5xd9370dUY4JllCQ8tdT4,37185
|
|
@@ -166,9 +167,9 @@ matrice_analytics/post_processing/usecases/weld_defect_detection.py,sha256=b0dAJ
|
|
|
166
167
|
matrice_analytics/post_processing/usecases/wildlife_monitoring.py,sha256=TMVHJ5GLezmqG7DywmqbLggqNXgpsb63MD7IR6kvDkk,43446
|
|
167
168
|
matrice_analytics/post_processing/usecases/windmill_maintenance.py,sha256=G1eqo3Z-HYmGJ6oeZYrpZwhpvqQ9Lc_T-6S7BLBXHeA,40498
|
|
168
169
|
matrice_analytics/post_processing/usecases/wound_segmentation.py,sha256=ehNX6VuWMB3xAnCySO3ra3Tf_5FUNg5LCSdq_91h374,38342
|
|
169
|
-
matrice_analytics/post_processing/usecases/color/clip.py,sha256=
|
|
170
|
+
matrice_analytics/post_processing/usecases/color/clip.py,sha256=EN8z3XIwkkmuhGcSjTWV0Os7tSVwZOL-svsxkzT21e4,27586
|
|
170
171
|
matrice_analytics/post_processing/usecases/color/color_map_utils.py,sha256=SP-AEVcjLmL8rxblu-ixqUJC2fqlcr7ab4hWo4Fcr_k,2677
|
|
171
|
-
matrice_analytics/post_processing/usecases/color/color_mapper.py,sha256=
|
|
172
|
+
matrice_analytics/post_processing/usecases/color/color_mapper.py,sha256=aUbs5bGxxKEg0CFZUIKE1zbABLr02ZB81HRUb_wdPfk,17458
|
|
172
173
|
matrice_analytics/post_processing/usecases/color/clip_processor/merges.txt,sha256=n9aR98gDkhDg_O0VhlRmxlgg0JtjmIsBdL_iXeKZBRo,524619
|
|
173
174
|
matrice_analytics/post_processing/usecases/color/clip_processor/preprocessor_config.json,sha256=j7VHQDZW6QGbCYLSMQsEW-85udKoEaDJh1blLUjiXbY,504
|
|
174
175
|
matrice_analytics/post_processing/usecases/color/clip_processor/special_tokens_map.json,sha256=LNs7gzGmDJL8HlWhPp_WH9IpPFpRJ1_czNYreABSUw4,588
|
|
@@ -188,8 +189,8 @@ matrice_analytics/post_processing/utils/format_utils.py,sha256=UTF7A5h9j0_S12xH9
|
|
|
188
189
|
matrice_analytics/post_processing/utils/geometry_utils.py,sha256=BWfdM6RsdJTTLR1GqkWfdwpjMEjTCJyuBxA4zVGKdfk,9623
|
|
189
190
|
matrice_analytics/post_processing/utils/smoothing_utils.py,sha256=78U-yucAcjUiZ0NIAc9NOUSIT0PWP1cqyIPA_Fdrjp0,14699
|
|
190
191
|
matrice_analytics/post_processing/utils/tracking_utils.py,sha256=rWxuotnJ3VLMHIBOud2KLcu4yZfDp7hVPWUtNAq_2xw,8288
|
|
191
|
-
matrice_analytics-0.1.
|
|
192
|
-
matrice_analytics-0.1.
|
|
193
|
-
matrice_analytics-0.1.
|
|
194
|
-
matrice_analytics-0.1.
|
|
195
|
-
matrice_analytics-0.1.
|
|
192
|
+
matrice_analytics-0.1.45.dist-info/licenses/LICENSE.txt,sha256=_uQUZpgO0mRYL5-fPoEvLSbNnLPv6OmbeEDCHXhK6Qc,1066
|
|
193
|
+
matrice_analytics-0.1.45.dist-info/METADATA,sha256=cejPbTOU7QL_WuBVD_azQBNbihZX1FM-aLK9QrM7x58,14378
|
|
194
|
+
matrice_analytics-0.1.45.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
195
|
+
matrice_analytics-0.1.45.dist-info/top_level.txt,sha256=STAPEU-e-rWTerXaspdi76T_eVRSrEfFpURSP7_Dt8E,18
|
|
196
|
+
matrice_analytics-0.1.45.dist-info/RECORD,,
|
|
File without changes
|
{matrice_analytics-0.1.43.dist-info → matrice_analytics-0.1.45.dist-info}/licenses/LICENSE.txt
RENAMED
|
File without changes
|
|
File without changes
|