nedo-vision-worker-core 0.4.1__tar.gz → 0.4.3__tar.gz

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 nedo-vision-worker-core might be problematic. Click here for more details.

Files changed (114) hide show
  1. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/PKG-INFO +1 -1
  2. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/__init__.py +1 -1
  3. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/pipeline/PipelineManager.py +14 -0
  4. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/pipeline/PipelineProcessor.py +18 -3
  5. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/pipeline/PipelineSyncThread.py +13 -0
  6. nedo_vision_worker_core-0.4.3/nedo_vision_worker_core/repositories/WorkerSourceRepository.py +56 -0
  7. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/streams/RTMPStreamer.py +1 -1
  8. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core.egg-info/PKG-INFO +1 -1
  9. nedo_vision_worker_core-0.4.1/nedo_vision_worker_core/repositories/WorkerSourceRepository.py +0 -21
  10. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/MANIFEST.in +0 -0
  11. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/README.md +0 -0
  12. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/ai/FrameDrawer.py +0 -0
  13. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/ai/ImageDebugger.py +0 -0
  14. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/ai/VideoDebugger.py +0 -0
  15. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/ai/__init__.py +0 -0
  16. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/callbacks/DetectionCallbackManager.py +0 -0
  17. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/callbacks/DetectionCallbackTypes.py +0 -0
  18. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/callbacks/__init__.py +0 -0
  19. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/cli.py +0 -0
  20. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/config/ConfigurationManager.py +0 -0
  21. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/config/__init__.py +0 -0
  22. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/core_service.py +0 -0
  23. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/database/DatabaseManager.py +0 -0
  24. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/database/__init__.py +0 -0
  25. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/detection/BaseDetector.py +0 -0
  26. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/detection/RFDETRDetector.py +0 -0
  27. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/detection/YOLODetector.py +0 -0
  28. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/detection/__init__.py +0 -0
  29. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/detection/detection_processing/DetectionProcessor.py +0 -0
  30. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/detection/detection_processing/HumanDetectionProcessor.py +0 -0
  31. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/detection/detection_processing/PPEDetectionProcessor.py +0 -0
  32. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/detection/detection_processing/__init__.py +0 -0
  33. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/doctor.py +0 -0
  34. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/blue/inner_corner.png +0 -0
  35. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/blue/inner_frame.png +0 -0
  36. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/blue/line.png +0 -0
  37. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/blue/top_left.png +0 -0
  38. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/blue/top_right.png +0 -0
  39. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/red/inner_corner.png +0 -0
  40. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/red/inner_frame.png +0 -0
  41. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/red/line.png +0 -0
  42. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/red/top_left.png +0 -0
  43. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/drawing_assets/red/top_right.png +0 -0
  44. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/boots-green.png +0 -0
  45. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/boots-red.png +0 -0
  46. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/gloves-green.png +0 -0
  47. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/gloves-red.png +0 -0
  48. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/goggles-green.png +0 -0
  49. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/goggles-red.png +0 -0
  50. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/helmet-green.png +0 -0
  51. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/helmet-red.png +0 -0
  52. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/mask-red.png +0 -0
  53. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/vest-green.png +0 -0
  54. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/icons/vest-red.png +0 -0
  55. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/__init__.py +0 -0
  56. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/ai_model.py +0 -0
  57. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/auth.py +0 -0
  58. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/config.py +0 -0
  59. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/dataset_source.py +0 -0
  60. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/logs.py +0 -0
  61. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/ppe_detection.py +0 -0
  62. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/ppe_detection_label.py +0 -0
  63. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/restricted_area_violation.py +0 -0
  64. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/user.py +0 -0
  65. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/worker_source.py +0 -0
  66. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/worker_source_pipeline.py +0 -0
  67. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/worker_source_pipeline_config.py +0 -0
  68. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/worker_source_pipeline_debug.py +0 -0
  69. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/models/worker_source_pipeline_detection.py +0 -0
  70. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/pipeline/ModelManager.py +0 -0
  71. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/pipeline/PipelineConfigManager.py +0 -0
  72. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/pipeline/PipelinePrepocessor.py +0 -0
  73. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/pipeline/__init__.py +0 -0
  74. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/preprocessing/ImageResizer.py +0 -0
  75. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/preprocessing/ImageRoi.py +0 -0
  76. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/preprocessing/Preprocessor.py +0 -0
  77. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/preprocessing/__init__.py +0 -0
  78. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/repositories/AIModelRepository.py +0 -0
  79. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/repositories/BaseRepository.py +0 -0
  80. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/repositories/PPEDetectionRepository.py +0 -0
  81. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/repositories/RestrictedAreaRepository.py +0 -0
  82. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/repositories/WorkerSourcePipelineDebugRepository.py +0 -0
  83. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/repositories/WorkerSourcePipelineDetectionRepository.py +0 -0
  84. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/repositories/WorkerSourcePipelineRepository.py +0 -0
  85. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/repositories/__init__.py +0 -0
  86. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/services/SharedVideoStreamServer.py +0 -0
  87. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/services/VideoSharingDaemon.py +0 -0
  88. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/services/VideoSharingDaemonManager.py +0 -0
  89. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/streams/SharedVideoDeviceManager.py +0 -0
  90. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/streams/StreamSyncThread.py +0 -0
  91. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/streams/VideoStream.py +0 -0
  92. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/streams/VideoStreamManager.py +0 -0
  93. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/streams/__init__.py +0 -0
  94. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/tracker/SFSORT.py +0 -0
  95. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/tracker/TrackerManager.py +0 -0
  96. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/tracker/__init__.py +0 -0
  97. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/util/BoundingBoxMetrics.py +0 -0
  98. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/util/DrawingUtils.py +0 -0
  99. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/util/ModelReadinessChecker.py +0 -0
  100. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/util/PersonAttributeMatcher.py +0 -0
  101. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/util/PersonRestrictedAreaMatcher.py +0 -0
  102. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/util/PipelinePreviewChecker.py +0 -0
  103. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/util/PlatformDetector.py +0 -0
  104. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/util/TablePrinter.py +0 -0
  105. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core/util/__init__.py +0 -0
  106. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core.egg-info/SOURCES.txt +0 -0
  107. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core.egg-info/dependency_links.txt +0 -0
  108. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core.egg-info/entry_points.txt +0 -0
  109. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core.egg-info/requires.txt +0 -0
  110. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/nedo_vision_worker_core.egg-info/top_level.txt +0 -0
  111. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/pyproject.toml +0 -0
  112. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/requirements.txt +0 -0
  113. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/setup.cfg +0 -0
  114. {nedo_vision_worker_core-0.4.1 → nedo_vision_worker_core-0.4.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nedo-vision-worker-core
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: Nedo Vision Worker Core Library for AI Vision Processing
5
5
  Author-email: Willy Achmat Fauzi <willy.achmat@gmail.com>
6
6
  Maintainer-email: Willy Achmat Fauzi <willy.achmat@gmail.com>
@@ -7,7 +7,7 @@ A library for running AI vision processing and detection in the Nedo Vision plat
7
7
  from .core_service import CoreService
8
8
  from .callbacks import DetectionType, CallbackTrigger, DetectionData, IntervalMetadata
9
9
 
10
- __version__ = "0.4.1"
10
+ __version__ = "0.4.3"
11
11
  __all__ = [
12
12
  "CoreService",
13
13
  "DetectionType",
@@ -31,6 +31,11 @@ class PipelineManager:
31
31
  self._stop_lock = threading.Lock()
32
32
  self.on_pipeline_stopped = on_pipeline_stopped
33
33
 
34
+ # Stagger pipeline startup to reduce CPU spikes
35
+ self._last_pipeline_start = 0
36
+ self._pipeline_start_delay = 1.0 # 1 second between pipeline starts
37
+ self._start_lock = threading.Lock()
38
+
34
39
  logging.info(f"🚀 PipelineManager initialized with {max_workers} worker threads")
35
40
 
36
41
  def start_pipeline(self, pipeline, detector):
@@ -46,6 +51,15 @@ class PipelineManager:
46
51
  logging.warning(f"⚠️ Pipeline {pipeline_id} is already running.")
47
52
  return
48
53
 
54
+ # Stagger pipeline starts to reduce CPU spikes
55
+ with self._start_lock:
56
+ time_since_last_start = time.time() - self._last_pipeline_start
57
+ if time_since_last_start < self._pipeline_start_delay:
58
+ delay = self._pipeline_start_delay - time_since_last_start
59
+ logging.info(f"⏳ Staggering pipeline {pipeline_id} start by {delay:.2f}s to reduce CPU spike")
60
+ time.sleep(delay)
61
+ self._last_pipeline_start = time.time()
62
+
49
63
  logging.info(f"🚀 Starting Pipeline processing for pipeline: {pipeline_id} | Source: {worker_source_id} ({pipeline.name})")
50
64
 
51
65
  # Acquire video stream
@@ -47,6 +47,10 @@ class PipelineProcessor:
47
47
  self.last_preview_check_time = 0
48
48
  self.preview_check_interval = 10.0 # Check every 10 seconds (reduced from 5s to save CPU)
49
49
  self.pipeline_repo = WorkerSourcePipelineRepository()
50
+
51
+ # RTMP frame rate limiting to reduce CPU
52
+ self.last_rtmp_frame_time = 0
53
+ self.rtmp_frame_interval = 1.0 / 25.0 # 25 FPS for RTMP (matching render FPS)
50
54
 
51
55
  self.detection_processor_codes = [
52
56
  PPEDetectionProcessor.code,
@@ -199,9 +203,17 @@ class PipelineProcessor:
199
203
  self._check_and_update_rtmp_streaming()
200
204
  last_preview_check = loop_start
201
205
 
206
+ # Only draw frames when actually needed (RTMP active or debug)
202
207
  should_draw = self.rtmp_streaming_active or self.debug_flag
203
208
 
204
- if should_draw:
209
+ # For RTMP, also check if it's time to send a frame (rate limiting)
210
+ should_draw_for_rtmp = (
211
+ self.rtmp_streaming_active and
212
+ self.rtmp_streamer is not None and
213
+ (loop_start - self.last_rtmp_frame_time >= self.rtmp_frame_interval)
214
+ )
215
+
216
+ if should_draw_for_rtmp or self.debug_flag:
205
217
  try:
206
218
  frame_to_draw = frame.copy()
207
219
  self.frame_drawer.draw_polygons(frame_to_draw)
@@ -215,7 +227,7 @@ class PipelineProcessor:
215
227
  logging.error(f"❌ Draw failed, using raw frame: {e}")
216
228
  drawn_frame = frame
217
229
  else:
218
- drawn_frame = frame
230
+ drawn_frame = None # Don't waste CPU drawing if not needed
219
231
 
220
232
  if self.debug_flag:
221
233
  tracked_objects_render = self._process_frame(frame)
@@ -235,13 +247,16 @@ class PipelineProcessor:
235
247
  try:
236
248
  self.rtmp_streamer = RTMPStreamer(self.pipeline_id)
237
249
  logging.info(f"🎬 RTMP streamer initialized for pipeline {pipeline_id} (preview requested)")
250
+ self.last_rtmp_frame_time = 0 # Reset frame time on new stream
238
251
  except Exception as e:
239
252
  logging.error(f"❌ Failed to initialize RTMP streamer for pipeline {pipeline_id}: {e}")
240
253
  self.rtmp_streamer = None
241
254
 
242
- if self.rtmp_streamer:
255
+ if self.rtmp_streamer and drawn_frame is not None:
256
+ # Frame already rate-limited by drawing logic above
243
257
  try:
244
258
  self.rtmp_streamer.push_frame(drawn_frame)
259
+ self.last_rtmp_frame_time = loop_start
245
260
  except Exception as e:
246
261
  logging.error(f"❌ RTMP push error for pipeline {pipeline_id}: {e}")
247
262
  if "initialization_failed" in str(e).lower():
@@ -5,6 +5,7 @@ import threading
5
5
  from typing import Dict, Set, Optional
6
6
  from ..repositories.WorkerSourcePipelineDebugRepository import WorkerSourcePipelineDebugRepository
7
7
  from ..repositories.WorkerSourcePipelineRepository import WorkerSourcePipelineRepository
8
+ from ..repositories.WorkerSourceRepository import WorkerSourceRepository
8
9
  from .PipelineManager import PipelineManager
9
10
  from .ModelManager import ModelManager
10
11
  from ..streams.VideoStreamManager import VideoStreamManager
@@ -19,6 +20,7 @@ class PipelineSyncThread(threading.Thread):
19
20
  self.polling_interval = polling_interval
20
21
  self.pipeline_repo = WorkerSourcePipelineRepository()
21
22
  self.debug_repo = WorkerSourcePipelineDebugRepository()
23
+ self.source_repo = WorkerSourceRepository()
22
24
  self.model_manager = ModelManager()
23
25
  self.running = True
24
26
  self.pipeline_manager = PipelineManager(video_manager, self.on_pipeline_stopped, max_workers)
@@ -82,6 +84,11 @@ class PipelineSyncThread(threading.Thread):
82
84
  pipeline.pipeline_status_code = 'run'
83
85
 
84
86
  if pipeline.pipeline_status_code == 'run':
87
+ # Check if source is connected before starting pipeline
88
+ if not self.source_repo.is_source_connected(pipeline.worker_source_id):
89
+ logging.warning(f"⚠️ Skipping pipeline {pid} ({pipeline.name}): Source {pipeline.worker_source_id} is disconnected")
90
+ continue
91
+
85
92
  detector = self.model_manager.get_detector(pipeline.ai_model_id)
86
93
 
87
94
  if not detector and pipeline.ai_model_id:
@@ -146,6 +153,12 @@ class PipelineSyncThread(threading.Thread):
146
153
  if requires_restart:
147
154
  logging.info(f"🔄 Restarting pipeline due to significant changes: {pid}")
148
155
  self.pipeline_manager.stop_pipeline(pid)
156
+
157
+ # Check if source is connected before restarting
158
+ if not self.source_repo.is_source_connected(db_pipeline.worker_source_id):
159
+ logging.warning(f"⚠️ Cannot restart pipeline {pid}: Source {db_pipeline.worker_source_id} is disconnected")
160
+ return
161
+
149
162
  self.pipeline_manager.start_pipeline(db_pipeline, db_detector)
150
163
  else:
151
164
  # Update config for minor changes that don't require restart
@@ -0,0 +1,56 @@
1
+ from .BaseRepository import BaseRepository
2
+ from ..models.worker_source import WorkerSourceEntity
3
+
4
+
5
+ class WorkerSourceRepository(BaseRepository):
6
+ def __init__(self):
7
+ super().__init__(db_name="config")
8
+
9
+ def get_worker_sources(self):
10
+ """
11
+ Fetch all worker sources from the local database in a single query.
12
+
13
+ Returns:
14
+ list: A list of WorkerSourceEntity records.
15
+ """
16
+ with self._get_session() as session:
17
+ session.expire_all()
18
+ sources = session.query(WorkerSourceEntity).all()
19
+ for source in sources:
20
+ session.expunge(source)
21
+ return sources
22
+
23
+ def get_worker_source(self, source_id: str):
24
+ """
25
+ Fetch a single worker source by ID.
26
+
27
+ Args:
28
+ source_id (str): The worker source ID
29
+
30
+ Returns:
31
+ WorkerSourceEntity: The worker source entity or None if not found
32
+ """
33
+ with self._get_session() as session:
34
+ session.expire_all()
35
+ source = session.query(WorkerSourceEntity).filter(
36
+ WorkerSourceEntity.id == source_id
37
+ ).first()
38
+ if source:
39
+ session.expunge(source)
40
+ return source
41
+
42
+ def is_source_connected(self, source_id: str) -> bool:
43
+ """
44
+ Check if a worker source is connected.
45
+
46
+ Args:
47
+ source_id (str): The worker source ID
48
+
49
+ Returns:
50
+ bool: True if source is connected, False otherwise
51
+ """
52
+ source = self.get_worker_source(source_id)
53
+ if not source:
54
+ return False
55
+
56
+ return source.status_code == "connected" if source.status_code else False
@@ -25,7 +25,7 @@ class RTMPStreamer:
25
25
  # Class-level lock to stagger stream initialization across all instances
26
26
  _initialization_lock = threading.Lock()
27
27
  _last_initialization_time = 0
28
- _min_initialization_delay = 0.5 # 500ms between stream starts
28
+ _min_initialization_delay = 1.5 # 1.5 seconds between stream starts (increased from 0.5s)
29
29
 
30
30
  def __init__(self, pipeline_id: str, fps: int = 25, bitrate: str = "1500k"):
31
31
  self.pipeline_id = pipeline_id
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nedo-vision-worker-core
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: Nedo Vision Worker Core Library for AI Vision Processing
5
5
  Author-email: Willy Achmat Fauzi <willy.achmat@gmail.com>
6
6
  Maintainer-email: Willy Achmat Fauzi <willy.achmat@gmail.com>
@@ -1,21 +0,0 @@
1
- from .BaseRepository import BaseRepository
2
- from ..models.worker_source import WorkerSourceEntity
3
-
4
-
5
- class WorkerSourceRepository(BaseRepository):
6
- def __init__(self):
7
- super().__init__(db_name="config")
8
-
9
- def get_worker_sources(self):
10
- """
11
- Fetch all worker sources from the local database in a single query.
12
-
13
- Returns:
14
- list: A list of WorkerSourceEntity records.
15
- """
16
- with self._get_session() as session:
17
- session.expire_all()
18
- sources = session.query(WorkerSourceEntity).all()
19
- for source in sources:
20
- session.expunge(source)
21
- return sources