matrice-analytics 0.1.60__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.
Files changed (196) hide show
  1. matrice_analytics/__init__.py +28 -0
  2. matrice_analytics/boundary_drawing_internal/README.md +305 -0
  3. matrice_analytics/boundary_drawing_internal/__init__.py +45 -0
  4. matrice_analytics/boundary_drawing_internal/boundary_drawing_internal.py +1207 -0
  5. matrice_analytics/boundary_drawing_internal/boundary_drawing_tool.py +429 -0
  6. matrice_analytics/boundary_drawing_internal/boundary_tool_template.html +1036 -0
  7. matrice_analytics/boundary_drawing_internal/data/.gitignore +12 -0
  8. matrice_analytics/boundary_drawing_internal/example_usage.py +206 -0
  9. matrice_analytics/boundary_drawing_internal/usage/README.md +110 -0
  10. matrice_analytics/boundary_drawing_internal/usage/boundary_drawer_launcher.py +102 -0
  11. matrice_analytics/boundary_drawing_internal/usage/simple_boundary_launcher.py +107 -0
  12. matrice_analytics/post_processing/README.md +455 -0
  13. matrice_analytics/post_processing/__init__.py +732 -0
  14. matrice_analytics/post_processing/advanced_tracker/README.md +650 -0
  15. matrice_analytics/post_processing/advanced_tracker/__init__.py +17 -0
  16. matrice_analytics/post_processing/advanced_tracker/base.py +99 -0
  17. matrice_analytics/post_processing/advanced_tracker/config.py +77 -0
  18. matrice_analytics/post_processing/advanced_tracker/kalman_filter.py +370 -0
  19. matrice_analytics/post_processing/advanced_tracker/matching.py +195 -0
  20. matrice_analytics/post_processing/advanced_tracker/strack.py +230 -0
  21. matrice_analytics/post_processing/advanced_tracker/tracker.py +367 -0
  22. matrice_analytics/post_processing/config.py +146 -0
  23. matrice_analytics/post_processing/core/__init__.py +63 -0
  24. matrice_analytics/post_processing/core/base.py +704 -0
  25. matrice_analytics/post_processing/core/config.py +3291 -0
  26. matrice_analytics/post_processing/core/config_utils.py +925 -0
  27. matrice_analytics/post_processing/face_reg/__init__.py +43 -0
  28. matrice_analytics/post_processing/face_reg/compare_similarity.py +556 -0
  29. matrice_analytics/post_processing/face_reg/embedding_manager.py +950 -0
  30. matrice_analytics/post_processing/face_reg/face_recognition.py +2234 -0
  31. matrice_analytics/post_processing/face_reg/face_recognition_client.py +606 -0
  32. matrice_analytics/post_processing/face_reg/people_activity_logging.py +321 -0
  33. matrice_analytics/post_processing/ocr/__init__.py +0 -0
  34. matrice_analytics/post_processing/ocr/easyocr_extractor.py +250 -0
  35. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/__init__.py +9 -0
  36. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/__init__.py +4 -0
  37. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/cli.py +33 -0
  38. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/dataset_stats.py +139 -0
  39. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/export.py +398 -0
  40. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/train.py +447 -0
  41. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/utils.py +129 -0
  42. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/valid.py +93 -0
  43. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/validate_dataset.py +240 -0
  44. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/visualize_augmentation.py +176 -0
  45. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/cli/visualize_predictions.py +96 -0
  46. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/core/__init__.py +3 -0
  47. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/core/process.py +246 -0
  48. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/core/types.py +60 -0
  49. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/core/utils.py +87 -0
  50. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/inference/__init__.py +3 -0
  51. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/inference/config.py +82 -0
  52. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/inference/hub.py +141 -0
  53. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/inference/plate_recognizer.py +323 -0
  54. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/py.typed +0 -0
  55. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/__init__.py +0 -0
  56. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/data/__init__.py +0 -0
  57. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/data/augmentation.py +101 -0
  58. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/data/dataset.py +97 -0
  59. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/__init__.py +0 -0
  60. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/config.py +114 -0
  61. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/layers.py +553 -0
  62. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/loss.py +55 -0
  63. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/metric.py +86 -0
  64. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/model_builders.py +95 -0
  65. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/model/model_schema.py +395 -0
  66. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/utilities/__init__.py +0 -0
  67. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/utilities/backend_utils.py +38 -0
  68. matrice_analytics/post_processing/ocr/fast_plate_ocr_py38/train/utilities/utils.py +214 -0
  69. matrice_analytics/post_processing/ocr/postprocessing.py +270 -0
  70. matrice_analytics/post_processing/ocr/preprocessing.py +52 -0
  71. matrice_analytics/post_processing/post_processor.py +1175 -0
  72. matrice_analytics/post_processing/test_cases/__init__.py +1 -0
  73. matrice_analytics/post_processing/test_cases/run_tests.py +143 -0
  74. matrice_analytics/post_processing/test_cases/test_advanced_customer_service.py +841 -0
  75. matrice_analytics/post_processing/test_cases/test_basic_counting_tracking.py +523 -0
  76. matrice_analytics/post_processing/test_cases/test_comprehensive.py +531 -0
  77. matrice_analytics/post_processing/test_cases/test_config.py +852 -0
  78. matrice_analytics/post_processing/test_cases/test_customer_service.py +585 -0
  79. matrice_analytics/post_processing/test_cases/test_data_generators.py +583 -0
  80. matrice_analytics/post_processing/test_cases/test_people_counting.py +510 -0
  81. matrice_analytics/post_processing/test_cases/test_processor.py +524 -0
  82. matrice_analytics/post_processing/test_cases/test_usecases.py +165 -0
  83. matrice_analytics/post_processing/test_cases/test_utilities.py +356 -0
  84. matrice_analytics/post_processing/test_cases/test_utils.py +743 -0
  85. matrice_analytics/post_processing/usecases/Histopathological_Cancer_Detection_img.py +604 -0
  86. matrice_analytics/post_processing/usecases/__init__.py +267 -0
  87. matrice_analytics/post_processing/usecases/abandoned_object_detection.py +797 -0
  88. matrice_analytics/post_processing/usecases/advanced_customer_service.py +1601 -0
  89. matrice_analytics/post_processing/usecases/age_detection.py +842 -0
  90. matrice_analytics/post_processing/usecases/age_gender_detection.py +1085 -0
  91. matrice_analytics/post_processing/usecases/anti_spoofing_detection.py +656 -0
  92. matrice_analytics/post_processing/usecases/assembly_line_detection.py +841 -0
  93. matrice_analytics/post_processing/usecases/banana_defect_detection.py +624 -0
  94. matrice_analytics/post_processing/usecases/basic_counting_tracking.py +667 -0
  95. matrice_analytics/post_processing/usecases/blood_cancer_detection_img.py +881 -0
  96. matrice_analytics/post_processing/usecases/car_damage_detection.py +834 -0
  97. matrice_analytics/post_processing/usecases/car_part_segmentation.py +946 -0
  98. matrice_analytics/post_processing/usecases/car_service.py +1601 -0
  99. matrice_analytics/post_processing/usecases/cardiomegaly_classification.py +864 -0
  100. matrice_analytics/post_processing/usecases/cell_microscopy_segmentation.py +897 -0
  101. matrice_analytics/post_processing/usecases/chicken_pose_detection.py +648 -0
  102. matrice_analytics/post_processing/usecases/child_monitoring.py +814 -0
  103. matrice_analytics/post_processing/usecases/color/clip.py +660 -0
  104. matrice_analytics/post_processing/usecases/color/clip_processor/merges.txt +48895 -0
  105. matrice_analytics/post_processing/usecases/color/clip_processor/preprocessor_config.json +28 -0
  106. matrice_analytics/post_processing/usecases/color/clip_processor/special_tokens_map.json +30 -0
  107. matrice_analytics/post_processing/usecases/color/clip_processor/tokenizer.json +245079 -0
  108. matrice_analytics/post_processing/usecases/color/clip_processor/tokenizer_config.json +32 -0
  109. matrice_analytics/post_processing/usecases/color/clip_processor/vocab.json +1 -0
  110. matrice_analytics/post_processing/usecases/color/color_map_utils.py +70 -0
  111. matrice_analytics/post_processing/usecases/color/color_mapper.py +468 -0
  112. matrice_analytics/post_processing/usecases/color_detection.py +1936 -0
  113. matrice_analytics/post_processing/usecases/color_map_utils.py +70 -0
  114. matrice_analytics/post_processing/usecases/concrete_crack_detection.py +827 -0
  115. matrice_analytics/post_processing/usecases/crop_weed_detection.py +781 -0
  116. matrice_analytics/post_processing/usecases/customer_service.py +1008 -0
  117. matrice_analytics/post_processing/usecases/defect_detection_products.py +936 -0
  118. matrice_analytics/post_processing/usecases/distracted_driver_detection.py +822 -0
  119. matrice_analytics/post_processing/usecases/drone_traffic_monitoring.py +585 -0
  120. matrice_analytics/post_processing/usecases/drowsy_driver_detection.py +829 -0
  121. matrice_analytics/post_processing/usecases/dwell_detection.py +829 -0
  122. matrice_analytics/post_processing/usecases/emergency_vehicle_detection.py +827 -0
  123. matrice_analytics/post_processing/usecases/face_emotion.py +813 -0
  124. matrice_analytics/post_processing/usecases/face_recognition.py +827 -0
  125. matrice_analytics/post_processing/usecases/fashion_detection.py +835 -0
  126. matrice_analytics/post_processing/usecases/field_mapping.py +902 -0
  127. matrice_analytics/post_processing/usecases/fire_detection.py +1146 -0
  128. matrice_analytics/post_processing/usecases/flare_analysis.py +836 -0
  129. matrice_analytics/post_processing/usecases/flower_segmentation.py +1006 -0
  130. matrice_analytics/post_processing/usecases/gas_leak_detection.py +837 -0
  131. matrice_analytics/post_processing/usecases/gender_detection.py +832 -0
  132. matrice_analytics/post_processing/usecases/human_activity_recognition.py +871 -0
  133. matrice_analytics/post_processing/usecases/intrusion_detection.py +1672 -0
  134. matrice_analytics/post_processing/usecases/leaf.py +821 -0
  135. matrice_analytics/post_processing/usecases/leaf_disease.py +840 -0
  136. matrice_analytics/post_processing/usecases/leak_detection.py +837 -0
  137. matrice_analytics/post_processing/usecases/license_plate_detection.py +1188 -0
  138. matrice_analytics/post_processing/usecases/license_plate_monitoring.py +1781 -0
  139. matrice_analytics/post_processing/usecases/litter_monitoring.py +717 -0
  140. matrice_analytics/post_processing/usecases/mask_detection.py +869 -0
  141. matrice_analytics/post_processing/usecases/natural_disaster.py +907 -0
  142. matrice_analytics/post_processing/usecases/parking.py +787 -0
  143. matrice_analytics/post_processing/usecases/parking_space_detection.py +822 -0
  144. matrice_analytics/post_processing/usecases/pcb_defect_detection.py +888 -0
  145. matrice_analytics/post_processing/usecases/pedestrian_detection.py +808 -0
  146. matrice_analytics/post_processing/usecases/people_counting.py +706 -0
  147. matrice_analytics/post_processing/usecases/people_counting_bckp.py +1683 -0
  148. matrice_analytics/post_processing/usecases/people_tracking.py +1842 -0
  149. matrice_analytics/post_processing/usecases/pipeline_detection.py +605 -0
  150. matrice_analytics/post_processing/usecases/plaque_segmentation_img.py +874 -0
  151. matrice_analytics/post_processing/usecases/pothole_segmentation.py +915 -0
  152. matrice_analytics/post_processing/usecases/ppe_compliance.py +645 -0
  153. matrice_analytics/post_processing/usecases/price_tag_detection.py +822 -0
  154. matrice_analytics/post_processing/usecases/proximity_detection.py +1901 -0
  155. matrice_analytics/post_processing/usecases/road_lane_detection.py +623 -0
  156. matrice_analytics/post_processing/usecases/road_traffic_density.py +832 -0
  157. matrice_analytics/post_processing/usecases/road_view_segmentation.py +915 -0
  158. matrice_analytics/post_processing/usecases/shelf_inventory_detection.py +583 -0
  159. matrice_analytics/post_processing/usecases/shoplifting_detection.py +822 -0
  160. matrice_analytics/post_processing/usecases/shopping_cart_analysis.py +899 -0
  161. matrice_analytics/post_processing/usecases/skin_cancer_classification_img.py +864 -0
  162. matrice_analytics/post_processing/usecases/smoker_detection.py +833 -0
  163. matrice_analytics/post_processing/usecases/solar_panel.py +810 -0
  164. matrice_analytics/post_processing/usecases/suspicious_activity_detection.py +1030 -0
  165. matrice_analytics/post_processing/usecases/template_usecase.py +380 -0
  166. matrice_analytics/post_processing/usecases/theft_detection.py +648 -0
  167. matrice_analytics/post_processing/usecases/traffic_sign_monitoring.py +724 -0
  168. matrice_analytics/post_processing/usecases/underground_pipeline_defect_detection.py +775 -0
  169. matrice_analytics/post_processing/usecases/underwater_pollution_detection.py +842 -0
  170. matrice_analytics/post_processing/usecases/vehicle_monitoring.py +1029 -0
  171. matrice_analytics/post_processing/usecases/warehouse_object_segmentation.py +899 -0
  172. matrice_analytics/post_processing/usecases/waterbody_segmentation.py +923 -0
  173. matrice_analytics/post_processing/usecases/weapon_detection.py +771 -0
  174. matrice_analytics/post_processing/usecases/weld_defect_detection.py +615 -0
  175. matrice_analytics/post_processing/usecases/wildlife_monitoring.py +898 -0
  176. matrice_analytics/post_processing/usecases/windmill_maintenance.py +834 -0
  177. matrice_analytics/post_processing/usecases/wound_segmentation.py +856 -0
  178. matrice_analytics/post_processing/utils/__init__.py +150 -0
  179. matrice_analytics/post_processing/utils/advanced_counting_utils.py +400 -0
  180. matrice_analytics/post_processing/utils/advanced_helper_utils.py +317 -0
  181. matrice_analytics/post_processing/utils/advanced_tracking_utils.py +461 -0
  182. matrice_analytics/post_processing/utils/alerting_utils.py +213 -0
  183. matrice_analytics/post_processing/utils/category_mapping_utils.py +94 -0
  184. matrice_analytics/post_processing/utils/color_utils.py +592 -0
  185. matrice_analytics/post_processing/utils/counting_utils.py +182 -0
  186. matrice_analytics/post_processing/utils/filter_utils.py +261 -0
  187. matrice_analytics/post_processing/utils/format_utils.py +293 -0
  188. matrice_analytics/post_processing/utils/geometry_utils.py +300 -0
  189. matrice_analytics/post_processing/utils/smoothing_utils.py +358 -0
  190. matrice_analytics/post_processing/utils/tracking_utils.py +234 -0
  191. matrice_analytics/py.typed +0 -0
  192. matrice_analytics-0.1.60.dist-info/METADATA +481 -0
  193. matrice_analytics-0.1.60.dist-info/RECORD +196 -0
  194. matrice_analytics-0.1.60.dist-info/WHEEL +5 -0
  195. matrice_analytics-0.1.60.dist-info/licenses/LICENSE.txt +21 -0
  196. matrice_analytics-0.1.60.dist-info/top_level.txt +1 -0
@@ -0,0 +1,841 @@
1
+ """
2
+ Test cases for AdvancedCustomerServiceUseCase.
3
+
4
+ This module provides comprehensive tests for the advanced customer service use case,
5
+ covering journey analysis, queue management, staff analytics, and business intelligence.
6
+ """
7
+
8
+ import pytest
9
+ import time
10
+ from unittest.mock import patch, MagicMock
11
+ from typing import Dict, List, Any
12
+
13
+ from ..usecases.advanced_customer_service import AdvancedCustomerServiceUseCase
14
+ from ..core.base import ProcessingContext, ProcessingStatus
15
+ from ..core.config import CustomerServiceConfig, TrackingConfig, AlertConfig
16
+ from .test_utilities import BasePostProcessingTest
17
+ from .test_data_generators import (
18
+ create_detection_results,
19
+ create_tracking_results,
20
+ create_customer_service_areas,
21
+ create_large_dataset
22
+ )
23
+
24
+
25
+ class TestAdvancedCustomerServiceUseCase(BasePostProcessingTest):
26
+ """Test AdvancedCustomerServiceUseCase functionality."""
27
+
28
+ def setUp(self):
29
+ """Set up test environment."""
30
+ super().setUp()
31
+ self.use_case = AdvancedCustomerServiceUseCase()
32
+ self.areas = create_customer_service_areas()
33
+ self.config = CustomerServiceConfig(
34
+ customer_areas=self.areas["customer_areas"],
35
+ staff_areas=self.areas["staff_areas"],
36
+ service_areas=self.areas["service_areas"],
37
+ staff_categories=["staff", "employee"],
38
+ customer_categories=["customer", "person"],
39
+ confidence_threshold=0.5
40
+ )
41
+
42
+ def test_use_case_initialization(self):
43
+ """Test use case initialization."""
44
+ assert self.use_case.name == "advanced_customer_service"
45
+ assert self.use_case.category == "sales"
46
+ assert hasattr(self.use_case, 'logger')
47
+
48
+ # Check advanced tracking structures
49
+ assert hasattr(self.use_case, 'customer_occupancy')
50
+ assert hasattr(self.use_case, 'staff_occupancy')
51
+ assert hasattr(self.use_case, 'service_occupancy')
52
+ assert hasattr(self.use_case, 'customer_journey')
53
+ assert hasattr(self.use_case, 'staff_availability')
54
+ assert hasattr(self.use_case, 'JOURNEY_STATES')
55
+
56
+ def test_get_config_schema(self):
57
+ """Test configuration schema retrieval."""
58
+ schema = self.use_case.get_config_schema()
59
+
60
+ assert schema["type"] == "object"
61
+ assert "properties" in schema
62
+ assert "confidence_threshold" in schema["properties"]
63
+ assert "customer_areas" in schema["properties"]
64
+ assert "staff_areas" in schema["properties"]
65
+ assert "service_areas" in schema["properties"]
66
+ assert "staff_categories" in schema["properties"]
67
+ assert "customer_categories" in schema["properties"]
68
+ assert "service_proximity_threshold" in schema["properties"]
69
+ assert "enable_journey_analysis" in schema["properties"]
70
+ assert "enable_queue_analytics" in schema["properties"]
71
+
72
+ # Check default values
73
+ assert schema["properties"]["confidence_threshold"]["default"] == 0.5
74
+ assert schema["properties"]["service_proximity_threshold"]["default"] == 100.0
75
+
76
+ def test_create_default_config(self):
77
+ """Test default config creation."""
78
+ config = self.use_case.create_default_config()
79
+
80
+ assert isinstance(config, CustomerServiceConfig)
81
+ assert config.category == "sales"
82
+ assert config.usecase == "advanced_customer_service"
83
+ assert config.confidence_threshold == 0.5
84
+ assert config.enable_tracking is True
85
+ assert config.staff_categories == ["staff", "employee"]
86
+ assert config.customer_categories == ["customer", "person"]
87
+
88
+ def test_create_default_config_with_overrides(self):
89
+ """Test default config creation with overrides."""
90
+ customer_areas = {"lobby": [[0, 0], [100, 0], [100, 100], [0, 100]]}
91
+ config = self.use_case.create_default_config(
92
+ category="retail",
93
+ confidence_threshold=0.8,
94
+ customer_areas=customer_areas,
95
+ service_proximity_threshold=150.0
96
+ )
97
+
98
+ assert config.category == "retail"
99
+ assert config.confidence_threshold == 0.8
100
+ assert config.customer_areas == customer_areas
101
+ assert config.service_proximity_threshold == 150.0
102
+
103
+ def test_process_mixed_detection_data_success(self):
104
+ """Test processing mixed staff and customer detection data."""
105
+ # Create mixed detection data
106
+ detection_data = []
107
+
108
+ # Add staff detections
109
+ staff_data = create_detection_results(
110
+ num_detections=3,
111
+ categories=["staff"],
112
+ confidence_range=(0.7, 0.9),
113
+ bbox_range=((10, 10, 50, 50), (60, 60, 100, 100))
114
+ )
115
+ detection_data.extend(staff_data)
116
+
117
+ # Add customer detections
118
+ customer_data = create_detection_results(
119
+ num_detections=8,
120
+ categories=["customer", "person"],
121
+ confidence_range=(0.6, 0.9),
122
+ bbox_range=((110, 110, 150, 150), (160, 160, 200, 200))
123
+ )
124
+ detection_data.extend(customer_data)
125
+
126
+ result = self.use_case.process(detection_data, self.config)
127
+
128
+ self.assert_processing_result_valid(result)
129
+ assert result.status == ProcessingStatus.SUCCESS
130
+ assert result.usecase == "advanced_customer_service"
131
+
132
+ # Check comprehensive analytics structure
133
+ assert "customer_queue_analytics" in result.data
134
+ assert "staff_management" in result.data
135
+ assert "service_area_analytics" in result.data
136
+ assert "customer_journey_analytics" in result.data
137
+ assert "business_intelligence" in result.data
138
+
139
+ # Verify staff and customer counts
140
+ staff_count = result.data["staff_management"]["total_staff_present"]
141
+ customer_count = result.data["customer_queue_analytics"]["total_customers"]
142
+ assert staff_count > 0
143
+ assert customer_count > 0
144
+
145
+ def test_process_tracking_data_with_journey_analysis(self):
146
+ """Test processing tracking data with customer journey analysis."""
147
+ tracking_data = create_tracking_results(
148
+ num_tracks=5,
149
+ categories=["customer", "staff"],
150
+ frames=10
151
+ )
152
+
153
+ config = CustomerServiceConfig(
154
+ customer_areas=self.areas["customer_areas"],
155
+ staff_areas=self.areas["staff_areas"],
156
+ service_areas=self.areas["service_areas"],
157
+ staff_categories=["staff"],
158
+ customer_categories=["customer"],
159
+ enable_tracking=True
160
+ )
161
+
162
+ result = self.use_case.process(tracking_data, config)
163
+
164
+ self.assert_processing_result_valid(result)
165
+
166
+ # Check journey analysis
167
+ journey_analytics = result.data["customer_journey_analytics"]
168
+ assert "active_journeys" in journey_analytics
169
+ assert "completed_journeys" in journey_analytics
170
+ assert "journey_states" in journey_analytics
171
+
172
+ # Check for journey state tracking
173
+ if journey_analytics["active_journeys"] > 0:
174
+ assert "journey_states" in journey_analytics
175
+ states = journey_analytics["journey_states"]
176
+ assert isinstance(states, dict)
177
+
178
+ def test_process_with_queue_analytics(self):
179
+ """Test processing with queue analytics enabled."""
180
+ detection_data = create_detection_results(
181
+ num_detections=15,
182
+ categories=["customer", "person"],
183
+ confidence_range=(0.6, 0.9)
184
+ )
185
+
186
+ config = CustomerServiceConfig(
187
+ customer_areas=self.areas["customer_areas"],
188
+ staff_areas=self.areas["staff_areas"],
189
+ service_areas=self.areas["service_areas"],
190
+ customer_categories=["customer", "person"],
191
+ staff_categories=["staff"],
192
+ enable_queue_analytics=True
193
+ )
194
+
195
+ result = self.use_case.process(detection_data, config)
196
+
197
+ self.assert_processing_result_valid(result)
198
+
199
+ # Check queue analytics
200
+ queue_analytics = result.data["customer_queue_analytics"]
201
+ assert "total_customers" in queue_analytics
202
+ assert "customers_by_area" in queue_analytics
203
+ assert "average_wait_time" in queue_analytics
204
+ assert "queue_length_by_area" in queue_analytics
205
+
206
+ # Verify queue metrics
207
+ assert queue_analytics["total_customers"] >= 0
208
+ assert isinstance(queue_analytics["customers_by_area"], dict)
209
+
210
+ def test_process_with_staff_management_analytics(self):
211
+ """Test processing with staff management analytics."""
212
+ # Create mixed data with staff and customers
213
+ detection_data = []
214
+
215
+ # Add staff detections in staff areas
216
+ staff_data = create_detection_results(
217
+ num_detections=4,
218
+ categories=["staff", "employee"],
219
+ confidence_range=(0.7, 0.9)
220
+ )
221
+ detection_data.extend(staff_data)
222
+
223
+ # Add customer detections
224
+ customer_data = create_detection_results(
225
+ num_detections=12,
226
+ categories=["customer"],
227
+ confidence_range=(0.6, 0.9)
228
+ )
229
+ detection_data.extend(customer_data)
230
+
231
+ result = self.use_case.process(detection_data, self.config)
232
+
233
+ self.assert_processing_result_valid(result)
234
+
235
+ # Check staff management analytics
236
+ staff_mgmt = result.data["staff_management"]
237
+ assert "total_staff_present" in staff_mgmt
238
+ assert "staff_by_area" in staff_mgmt
239
+ assert "staff_availability" in staff_mgmt
240
+ assert "staff_efficiency" in staff_mgmt
241
+ assert "active_services" in staff_mgmt
242
+
243
+ # Verify staff metrics
244
+ assert staff_mgmt["total_staff_present"] >= 0
245
+ assert isinstance(staff_mgmt["staff_by_area"], dict)
246
+ assert isinstance(staff_mgmt["staff_availability"], dict)
247
+
248
+ def test_process_with_service_area_analytics(self):
249
+ """Test processing with service area analytics."""
250
+ detection_data = create_detection_results(
251
+ num_detections=20,
252
+ categories=["customer", "staff"],
253
+ confidence_range=(0.6, 0.9)
254
+ )
255
+
256
+ result = self.use_case.process(detection_data, self.config)
257
+
258
+ self.assert_processing_result_valid(result)
259
+
260
+ # Check service area analytics
261
+ service_analytics = result.data["service_area_analytics"]
262
+ assert "total_service_interactions" in service_analytics
263
+ assert "service_areas_occupancy" in service_analytics
264
+ assert "average_service_time" in service_analytics
265
+ assert "service_efficiency" in service_analytics
266
+
267
+ # Verify service metrics
268
+ assert service_analytics["total_service_interactions"] >= 0
269
+ assert isinstance(service_analytics["service_areas_occupancy"], dict)
270
+
271
+ def test_process_with_business_intelligence(self):
272
+ """Test processing with business intelligence metrics."""
273
+ detection_data = create_detection_results(
274
+ num_detections=30,
275
+ categories=["customer", "staff"],
276
+ confidence_range=(0.6, 0.9)
277
+ )
278
+
279
+ result = self.use_case.process(detection_data, self.config)
280
+
281
+ self.assert_processing_result_valid(result)
282
+
283
+ # Check business intelligence
284
+ bi = result.data["business_intelligence"]
285
+ assert "customer_to_staff_ratio" in bi
286
+ assert "service_capacity_utilization" in bi
287
+ assert "peak_occupancy_times" in bi
288
+ assert "customer_flow_patterns" in bi
289
+ assert "service_bottlenecks" in bi
290
+
291
+ # Verify BI metrics
292
+ assert isinstance(bi["customer_to_staff_ratio"], (int, float))
293
+ assert isinstance(bi["service_capacity_utilization"], (int, float))
294
+ assert isinstance(bi["peak_occupancy_times"], dict)
295
+
296
+ def test_process_with_alerts(self):
297
+ """Test processing with alert generation."""
298
+ detection_data = create_detection_results(
299
+ num_detections=25,
300
+ categories=["customer", "staff"]
301
+ )
302
+
303
+ alert_config = AlertConfig(
304
+ occupancy_thresholds={"customer_area": 15, "service_area": 8},
305
+ dwell_time_threshold=300.0, # 5 minutes
306
+ service_time_threshold=600.0, # 10 minutes
307
+ alert_cooldown=60.0
308
+ )
309
+
310
+ config = CustomerServiceConfig(
311
+ customer_areas=self.areas["customer_areas"],
312
+ staff_areas=self.areas["staff_areas"],
313
+ service_areas=self.areas["service_areas"],
314
+ customer_categories=["customer"],
315
+ staff_categories=["staff"],
316
+ alert_config=alert_config
317
+ )
318
+
319
+ result = self.use_case.process(detection_data, config)
320
+
321
+ self.assert_processing_result_valid(result)
322
+
323
+ # Check for alerts if thresholds are exceeded
324
+ if "alerts" in result.data and len(result.data["alerts"]) > 0:
325
+ alert = result.data["alerts"][0]
326
+ assert "type" in alert
327
+ assert "message" in alert
328
+ assert "timestamp" in alert
329
+ assert alert["type"] in ["occupancy_threshold", "service_time", "dwell_time"]
330
+
331
+ def test_process_empty_data(self):
332
+ """Test processing empty data."""
333
+ result = self.use_case.process([], self.config)
334
+
335
+ self.assert_processing_result_valid(result)
336
+
337
+ # Should have zero counts but valid structure
338
+ assert result.data["customer_queue_analytics"]["total_customers"] == 0
339
+ assert result.data["staff_management"]["total_staff_present"] == 0
340
+ assert result.data["service_area_analytics"]["total_service_interactions"] == 0
341
+ assert len(result.insights) > 0
342
+ assert "No activity detected" in result.summary or "No objects detected" in result.summary
343
+
344
+ def test_process_invalid_data_format(self):
345
+ """Test processing invalid data format."""
346
+ invalid_data = "not_a_list_or_dict"
347
+
348
+ result = self.use_case.process(invalid_data, self.config)
349
+
350
+ assert result.status == ProcessingStatus.ERROR
351
+ assert result.error_message is not None
352
+ assert "Invalid data format" in result.error_message or "Failed to process" in result.error_message
353
+
354
+ def test_customer_journey_state_transitions(self):
355
+ """Test customer journey state transitions."""
356
+ # Create tracking data that simulates customer movement
357
+ tracking_data = [
358
+ {
359
+ "track_id": 1,
360
+ "bbox": [10, 10, 50, 50],
361
+ "confidence": 0.8,
362
+ "category": "customer",
363
+ "frame_id": 1
364
+ },
365
+ {
366
+ "track_id": 1,
367
+ "bbox": [60, 60, 100, 100],
368
+ "confidence": 0.8,
369
+ "category": "customer",
370
+ "frame_id": 2
371
+ },
372
+ {
373
+ "track_id": 1,
374
+ "bbox": [110, 110, 150, 150],
375
+ "confidence": 0.8,
376
+ "category": "customer",
377
+ "frame_id": 3
378
+ }
379
+ ]
380
+
381
+ config = CustomerServiceConfig(
382
+ customer_areas=self.areas["customer_areas"],
383
+ staff_areas=self.areas["staff_areas"],
384
+ service_areas=self.areas["service_areas"],
385
+ customer_categories=["customer"],
386
+ staff_categories=["staff"],
387
+ enable_journey_analysis=True
388
+ )
389
+
390
+ result = self.use_case.process(tracking_data, config)
391
+
392
+ self.assert_processing_result_valid(result)
393
+
394
+ # Check journey analytics
395
+ journey_analytics = result.data["customer_journey_analytics"]
396
+ assert "active_journeys" in journey_analytics
397
+
398
+ # Should track the customer journey
399
+ if journey_analytics["active_journeys"] > 0:
400
+ assert "journey_states" in journey_analytics
401
+
402
+ def test_staff_efficiency_calculation(self):
403
+ """Test staff efficiency calculation."""
404
+ # Create data with staff serving customers
405
+ detection_data = []
406
+
407
+ # Add staff detections
408
+ staff_data = [
409
+ {"bbox": [10, 10, 50, 50], "confidence": 0.9, "category": "staff", "track_id": 101},
410
+ {"bbox": [200, 200, 240, 240], "confidence": 0.9, "category": "staff", "track_id": 102}
411
+ ]
412
+ detection_data.extend(staff_data)
413
+
414
+ # Add customer detections near staff
415
+ customer_data = [
416
+ {"bbox": [15, 15, 45, 45], "confidence": 0.8, "category": "customer", "track_id": 201},
417
+ {"bbox": [25, 25, 55, 55], "confidence": 0.8, "category": "customer", "track_id": 202},
418
+ {"bbox": [205, 205, 235, 235], "confidence": 0.8, "category": "customer", "track_id": 203}
419
+ ]
420
+ detection_data.extend(customer_data)
421
+
422
+ config = CustomerServiceConfig(
423
+ customer_areas=self.areas["customer_areas"],
424
+ staff_areas=self.areas["staff_areas"],
425
+ service_areas=self.areas["service_areas"],
426
+ customer_categories=["customer"],
427
+ staff_categories=["staff"],
428
+ service_proximity_threshold=50.0 # Close proximity
429
+ )
430
+
431
+ result = self.use_case.process(detection_data, config)
432
+
433
+ self.assert_processing_result_valid(result)
434
+
435
+ # Check staff efficiency metrics
436
+ staff_mgmt = result.data["staff_management"]
437
+ assert "staff_efficiency" in staff_mgmt
438
+
439
+ # Should have efficiency data if staff are serving customers
440
+ efficiency = staff_mgmt["staff_efficiency"]
441
+ assert isinstance(efficiency, dict)
442
+
443
+ def test_service_proximity_detection(self):
444
+ """Test service proximity detection between staff and customers."""
445
+ # Create data with staff and customers in close proximity
446
+ detection_data = [
447
+ # Staff member
448
+ {"bbox": [100, 100, 140, 140], "confidence": 0.9, "category": "staff", "track_id": 1},
449
+ # Customer very close to staff (should be detected as service interaction)
450
+ {"bbox": [110, 110, 150, 150], "confidence": 0.8, "category": "customer", "track_id": 2},
451
+ # Customer far from staff (should not be service interaction)
452
+ {"bbox": [300, 300, 340, 340], "confidence": 0.8, "category": "customer", "track_id": 3}
453
+ ]
454
+
455
+ config = CustomerServiceConfig(
456
+ customer_areas=self.areas["customer_areas"],
457
+ staff_areas=self.areas["staff_areas"],
458
+ service_areas=self.areas["service_areas"],
459
+ customer_categories=["customer"],
460
+ staff_categories=["staff"],
461
+ service_proximity_threshold=80.0 # 80 pixel threshold
462
+ )
463
+
464
+ result = self.use_case.process(detection_data, config)
465
+
466
+ self.assert_processing_result_valid(result)
467
+
468
+ # Check service interactions
469
+ service_analytics = result.data["service_area_analytics"]
470
+ interactions = service_analytics["total_service_interactions"]
471
+
472
+ # Should detect at least one service interaction (staff + close customer)
473
+ assert interactions >= 0 # May be 0 if proximity calculation differs
474
+
475
+ def test_peak_occupancy_tracking(self):
476
+ """Test peak occupancy tracking."""
477
+ detection_data = create_detection_results(
478
+ num_detections=40,
479
+ categories=["customer", "staff"],
480
+ confidence_range=(0.6, 0.9)
481
+ )
482
+
483
+ result = self.use_case.process(detection_data, self.config)
484
+
485
+ self.assert_processing_result_valid(result)
486
+
487
+ # Check peak occupancy in business intelligence
488
+ bi = result.data["business_intelligence"]
489
+ peak_times = bi["peak_occupancy_times"]
490
+
491
+ assert isinstance(peak_times, dict)
492
+ # Should track current timestamp as peak if significant activity
493
+ if result.data["customer_queue_analytics"]["total_customers"] > 0:
494
+ assert len(peak_times) >= 0
495
+
496
+ def test_customer_flow_patterns(self):
497
+ """Test customer flow pattern analysis."""
498
+ # Create tracking data showing customer movement patterns
499
+ tracking_data = []
500
+
501
+ # Simulate customers moving through different areas
502
+ for track_id in range(1, 6):
503
+ for frame in range(1, 4):
504
+ x_offset = frame * 50
505
+ y_offset = track_id * 30
506
+ tracking_data.append({
507
+ "track_id": track_id,
508
+ "bbox": [x_offset, y_offset, x_offset + 40, y_offset + 40],
509
+ "confidence": 0.8,
510
+ "category": "customer",
511
+ "frame_id": frame
512
+ })
513
+
514
+ config = CustomerServiceConfig(
515
+ customer_areas=self.areas["customer_areas"],
516
+ staff_areas=self.areas["staff_areas"],
517
+ service_areas=self.areas["service_areas"],
518
+ customer_categories=["customer"],
519
+ staff_categories=["staff"],
520
+ enable_journey_analysis=True
521
+ )
522
+
523
+ result = self.use_case.process(tracking_data, config)
524
+
525
+ self.assert_processing_result_valid(result)
526
+
527
+ # Check customer flow patterns
528
+ bi = result.data["business_intelligence"]
529
+ flow_patterns = bi["customer_flow_patterns"]
530
+
531
+ assert isinstance(flow_patterns, dict)
532
+ # Should have some flow analysis if customers are moving
533
+ if result.data["customer_queue_analytics"]["total_customers"] > 0:
534
+ assert "movement_patterns" in flow_patterns or len(flow_patterns) >= 0
535
+
536
+ def test_process_with_context(self):
537
+ """Test processing with context information."""
538
+ detection_data = create_detection_results(10, ["customer", "staff"])
539
+ context = ProcessingContext(
540
+ input_size=len(detection_data),
541
+ confidence_threshold=0.5,
542
+ enable_tracking=True,
543
+ enable_analytics=True,
544
+ metadata={"location": "retail_store", "camera_id": "cam_01"}
545
+ )
546
+
547
+ result = self.use_case.process(detection_data, self.config, context)
548
+
549
+ self.assert_processing_result_valid(result)
550
+ assert result.context == context
551
+ assert result.processing_time > 0
552
+ assert result.context.processing_time is not None
553
+
554
+ def test_process_performance_large_dataset(self):
555
+ """Test processing performance with large dataset."""
556
+ large_data = create_large_dataset(500, ["customer", "staff"])
557
+
558
+ start_time = time.time()
559
+ result = self.use_case.process(large_data, self.config)
560
+ processing_time = time.time() - start_time
561
+
562
+ self.assert_processing_result_valid(result)
563
+ assert processing_time < 10.0 # Should process within 10 seconds
564
+
565
+ # Check that all analytics components are present
566
+ assert "customer_queue_analytics" in result.data
567
+ assert "staff_management" in result.data
568
+ assert "service_area_analytics" in result.data
569
+ assert "business_intelligence" in result.data
570
+
571
+ # Check performance metrics
572
+ assert "processing_time" in result.metrics
573
+ assert result.metrics["processing_time"] > 0
574
+
575
+ def test_insights_generation_comprehensive(self):
576
+ """Test comprehensive insight generation."""
577
+ detection_data = create_detection_results(
578
+ num_detections=35,
579
+ categories=["customer", "staff"],
580
+ confidence_range=(0.6, 0.9)
581
+ )
582
+
583
+ result = self.use_case.process(detection_data, self.config)
584
+
585
+ self.assert_processing_result_valid(result)
586
+ assert len(result.insights) > 0
587
+
588
+ # Check for different types of insights
589
+ insight_text = " ".join(result.insights).lower()
590
+
591
+ # Should have customer-related insights
592
+ assert any(word in insight_text for word in ["customer", "customers", "service", "staff"])
593
+
594
+ # Should provide business intelligence insights
595
+ if result.data["customer_queue_analytics"]["total_customers"] > 0:
596
+ assert len(result.insights) >= 2 # Multiple insights for comprehensive analysis
597
+
598
+ def test_metrics_calculation_comprehensive(self):
599
+ """Test comprehensive metrics calculation."""
600
+ detection_data = create_detection_results(25, ["customer", "staff"])
601
+
602
+ result = self.use_case.process(detection_data, self.config)
603
+
604
+ self.assert_processing_result_valid(result)
605
+ assert "metrics" in result.__dict__
606
+
607
+ # Check for comprehensive metrics
608
+ expected_metrics = [
609
+ "total_objects_processed",
610
+ "unique_categories",
611
+ "processing_time",
612
+ "customer_count",
613
+ "staff_count",
614
+ "service_interactions",
615
+ "analytics_computed"
616
+ ]
617
+
618
+ for metric in expected_metrics:
619
+ if metric in result.metrics:
620
+ assert result.metrics[metric] >= 0
621
+
622
+ def test_error_handling_malformed_areas(self):
623
+ """Test error handling with malformed area definitions."""
624
+ malformed_config = CustomerServiceConfig(
625
+ customer_areas={"invalid_area": [[0, 0], [100]]}, # Invalid polygon
626
+ staff_areas=self.areas["staff_areas"],
627
+ service_areas=self.areas["service_areas"],
628
+ customer_categories=["customer"],
629
+ staff_categories=["staff"]
630
+ )
631
+
632
+ detection_data = create_detection_results(5, ["customer"])
633
+
634
+ # Should handle gracefully or provide validation error
635
+ result = self.use_case.process(detection_data, malformed_config)
636
+
637
+ # Either processes successfully with warnings or fails with clear error
638
+ assert result.status in [ProcessingStatus.SUCCESS, ProcessingStatus.WARNING, ProcessingStatus.ERROR]
639
+ if result.status == ProcessingStatus.WARNING:
640
+ assert len(result.warnings) > 0
641
+ elif result.status == ProcessingStatus.ERROR:
642
+ assert result.error_message is not None
643
+
644
+ def test_memory_stability_advanced(self):
645
+ """Test memory stability with repeated advanced processing."""
646
+ detection_data = create_detection_results(100, ["customer", "staff"])
647
+
648
+ # Process multiple times to check for memory leaks
649
+ for i in range(5):
650
+ result = self.use_case.process(detection_data, self.config)
651
+ self.assert_processing_result_valid(result)
652
+
653
+ # Verify all advanced analytics are computed
654
+ assert "customer_queue_analytics" in result.data
655
+ assert "staff_management" in result.data
656
+ assert "service_area_analytics" in result.data
657
+ assert "business_intelligence" in result.data
658
+
659
+ # If we reach here without crashes, memory is likely stable
660
+ assert True
661
+
662
+
663
+ class TestAdvancedCustomerServiceIntegration(BasePostProcessingTest):
664
+ """Integration tests for AdvancedCustomerServiceUseCase."""
665
+
666
+ def setUp(self):
667
+ """Set up test environment."""
668
+ super().setUp()
669
+ self.use_case = AdvancedCustomerServiceUseCase()
670
+ self.areas = create_customer_service_areas()
671
+
672
+ def test_end_to_end_retail_store_scenario(self):
673
+ """Test end-to-end retail store customer service scenario."""
674
+ # Simulate busy retail store with staff and customers
675
+ detection_data = []
676
+
677
+ # Add staff members in different areas
678
+ staff_data = [
679
+ {"bbox": [50, 50, 90, 90], "confidence": 0.9, "category": "staff", "track_id": 101},
680
+ {"bbox": [250, 250, 290, 290], "confidence": 0.9, "category": "staff", "track_id": 102},
681
+ {"bbox": [450, 450, 490, 490], "confidence": 0.9, "category": "staff", "track_id": 103}
682
+ ]
683
+ detection_data.extend(staff_data)
684
+
685
+ # Add customers in various states
686
+ customer_data = create_detection_results(
687
+ num_detections=20,
688
+ categories=["customer"],
689
+ confidence_range=(0.6, 0.9)
690
+ )
691
+ detection_data.extend(customer_data)
692
+
693
+ config = CustomerServiceConfig(
694
+ category="retail",
695
+ customer_areas=self.areas["customer_areas"],
696
+ staff_areas=self.areas["staff_areas"],
697
+ service_areas=self.areas["service_areas"],
698
+ customer_categories=["customer"],
699
+ staff_categories=["staff"],
700
+ service_proximity_threshold=100.0,
701
+ enable_journey_analysis=True,
702
+ enable_queue_analytics=True,
703
+ alert_config=AlertConfig(
704
+ occupancy_thresholds={"customer_area": 15},
705
+ service_time_threshold=300.0
706
+ )
707
+ )
708
+
709
+ result = self.use_case.process(detection_data, config)
710
+
711
+ self.assert_processing_result_valid(result)
712
+ assert result.category == "retail"
713
+
714
+ # Verify comprehensive analytics
715
+ assert result.data["customer_queue_analytics"]["total_customers"] > 0
716
+ assert result.data["staff_management"]["total_staff_present"] == 3
717
+
718
+ # Check business intelligence metrics
719
+ bi = result.data["business_intelligence"]
720
+ assert bi["customer_to_staff_ratio"] > 0
721
+ assert isinstance(bi["service_capacity_utilization"], (int, float))
722
+
723
+ # Verify insights are business-relevant
724
+ insight_text = " ".join(result.insights).lower()
725
+ assert any(word in insight_text for word in ["customer", "staff", "service", "retail"])
726
+
727
+ def test_end_to_end_bank_branch_scenario(self):
728
+ """Test end-to-end bank branch customer service scenario."""
729
+ # Simulate bank branch with tellers and customers
730
+ detection_data = []
731
+
732
+ # Add bank tellers (staff)
733
+ teller_data = [
734
+ {"bbox": [100, 100, 140, 140], "confidence": 0.95, "category": "staff", "track_id": 201},
735
+ {"bbox": [300, 100, 340, 140], "confidence": 0.95, "category": "staff", "track_id": 202}
736
+ ]
737
+ detection_data.extend(teller_data)
738
+
739
+ # Add customers waiting and being served
740
+ customer_data = create_detection_results(
741
+ num_detections=12,
742
+ categories=["customer", "person"],
743
+ confidence_range=(0.7, 0.9)
744
+ )
745
+ detection_data.extend(customer_data)
746
+
747
+ config = CustomerServiceConfig(
748
+ category="banking",
749
+ customer_areas=self.areas["customer_areas"],
750
+ staff_areas=self.areas["staff_areas"],
751
+ service_areas=self.areas["service_areas"],
752
+ customer_categories=["customer", "person"],
753
+ staff_categories=["staff"],
754
+ service_proximity_threshold=80.0,
755
+ max_service_time=900.0, # 15 minutes max service
756
+ enable_journey_analysis=True,
757
+ enable_queue_analytics=True,
758
+ alert_config=AlertConfig(
759
+ occupancy_thresholds={"customer_area": 10},
760
+ service_time_threshold=600.0, # 10 minutes
761
+ dwell_time_threshold=1200.0 # 20 minutes max wait
762
+ )
763
+ )
764
+
765
+ result = self.use_case.process(detection_data, config)
766
+
767
+ self.assert_processing_result_valid(result)
768
+ assert result.category == "banking"
769
+
770
+ # Verify banking-specific analytics
771
+ queue_analytics = result.data["customer_queue_analytics"]
772
+ staff_mgmt = result.data["staff_management"]
773
+
774
+ assert queue_analytics["total_customers"] > 0
775
+ assert staff_mgmt["total_staff_present"] == 2
776
+
777
+ # Check for appropriate customer-to-staff ratio for banking
778
+ bi = result.data["business_intelligence"]
779
+ ratio = bi["customer_to_staff_ratio"]
780
+ assert ratio > 0
781
+
782
+ # Banking should have insights about wait times and service efficiency
783
+ insight_text = " ".join(result.insights).lower()
784
+ assert any(word in insight_text for word in ["customer", "service", "wait", "staff"])
785
+
786
+ def test_end_to_end_restaurant_scenario(self):
787
+ """Test end-to-end restaurant customer service scenario."""
788
+ # Simulate restaurant with servers and diners
789
+ detection_data = []
790
+
791
+ # Add restaurant staff (servers, hosts)
792
+ server_data = [
793
+ {"bbox": [150, 150, 190, 190], "confidence": 0.9, "category": "staff", "track_id": 301},
794
+ {"bbox": [350, 350, 390, 390], "confidence": 0.9, "category": "staff", "track_id": 302},
795
+ {"bbox": [50, 350, 90, 390], "confidence": 0.9, "category": "staff", "track_id": 303}
796
+ ]
797
+ detection_data.extend(server_data)
798
+
799
+ # Add customers/diners
800
+ customer_data = create_detection_results(
801
+ num_detections=25,
802
+ categories=["customer", "person"],
803
+ confidence_range=(0.6, 0.9)
804
+ )
805
+ detection_data.extend(customer_data)
806
+
807
+ config = CustomerServiceConfig(
808
+ category="restaurant",
809
+ customer_areas=self.areas["customer_areas"],
810
+ staff_areas=self.areas["staff_areas"],
811
+ service_areas=self.areas["service_areas"],
812
+ customer_categories=["customer", "person"],
813
+ staff_categories=["staff"],
814
+ service_proximity_threshold=120.0, # Larger area for restaurant service
815
+ max_service_time=3600.0, # 1 hour max dining time
816
+ buffer_time=5.0,
817
+ enable_journey_analysis=True,
818
+ enable_queue_analytics=True
819
+ )
820
+
821
+ result = self.use_case.process(detection_data, config)
822
+
823
+ self.assert_processing_result_valid(result)
824
+ assert result.category == "restaurant"
825
+
826
+ # Verify restaurant-specific metrics
827
+ assert result.data["customer_queue_analytics"]["total_customers"] > 0
828
+ assert result.data["staff_management"]["total_staff_present"] == 3
829
+
830
+ # Restaurant should have different service patterns
831
+ service_analytics = result.data["service_area_analytics"]
832
+ assert "total_service_interactions" in service_analytics
833
+
834
+ # Check for restaurant-relevant insights
835
+ insight_text = " ".join(result.insights).lower()
836
+ assert any(word in insight_text for word in ["customer", "staff", "service", "dining"])
837
+
838
+ # Business intelligence should reflect restaurant operations
839
+ bi = result.data["business_intelligence"]
840
+ assert bi["customer_to_staff_ratio"] > 0
841
+ assert isinstance(bi["service_capacity_utilization"], (int, float))