nedo-vision-worker-core 0.3.6__py3-none-any.whl → 0.3.7__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 nedo-vision-worker-core might be problematic. Click here for more details.
- nedo_vision_worker_core/__init__.py +1 -1
- nedo_vision_worker_core/models/worker_source_pipeline.py +2 -1
- nedo_vision_worker_core/pipeline/PipelineProcessor.py +68 -19
- nedo_vision_worker_core/util/PipelinePreviewChecker.py +50 -0
- {nedo_vision_worker_core-0.3.6.dist-info → nedo_vision_worker_core-0.3.7.dist-info}/METADATA +1 -1
- {nedo_vision_worker_core-0.3.6.dist-info → nedo_vision_worker_core-0.3.7.dist-info}/RECORD +9 -8
- {nedo_vision_worker_core-0.3.6.dist-info → nedo_vision_worker_core-0.3.7.dist-info}/WHEEL +0 -0
- {nedo_vision_worker_core-0.3.6.dist-info → nedo_vision_worker_core-0.3.7.dist-info}/entry_points.txt +0 -0
- {nedo_vision_worker_core-0.3.6.dist-info → nedo_vision_worker_core-0.3.7.dist-info}/top_level.txt +0 -0
|
@@ -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.3.
|
|
10
|
+
__version__ = "0.3.7"
|
|
11
11
|
__all__ = [
|
|
12
12
|
"CoreService",
|
|
13
13
|
"DetectionType",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from sqlalchemy import Column, String
|
|
1
|
+
from sqlalchemy import Column, String, DateTime
|
|
2
2
|
from sqlalchemy.orm import relationship
|
|
3
3
|
from ..database.DatabaseManager import Base
|
|
4
4
|
|
|
@@ -13,6 +13,7 @@ class WorkerSourcePipelineEntity(Base):
|
|
|
13
13
|
ai_model_id = Column(String, nullable=True)
|
|
14
14
|
pipeline_status_code = Column(String, nullable=False)
|
|
15
15
|
location_name = Column(String, nullable=True)
|
|
16
|
+
last_preview_request_at = Column(DateTime, nullable=True)
|
|
16
17
|
|
|
17
18
|
worker_source_pipeline_configs = relationship(
|
|
18
19
|
"WorkerSourcePipelineConfigEntity",
|
|
@@ -8,12 +8,14 @@ from .PipelineConfigManager import PipelineConfigManager
|
|
|
8
8
|
from .PipelinePrepocessor import PipelinePrepocessor
|
|
9
9
|
from ..repositories.WorkerSourcePipelineDebugRepository import WorkerSourcePipelineDebugRepository
|
|
10
10
|
from ..repositories.WorkerSourcePipelineDetectionRepository import WorkerSourcePipelineDetectionRepository
|
|
11
|
+
from ..repositories.WorkerSourcePipelineRepository import WorkerSourcePipelineRepository
|
|
11
12
|
from ..streams.VideoStreamManager import VideoStreamManager
|
|
12
13
|
from ..ai.VideoDebugger import VideoDebugger
|
|
13
14
|
from ..ai.FrameDrawer import FrameDrawer
|
|
14
15
|
from ..tracker.TrackerManager import TrackerManager
|
|
15
16
|
from ..detection.BaseDetector import BaseDetector
|
|
16
17
|
from ..streams.RTMPStreamer import RTMPStreamer
|
|
18
|
+
from ..util.PipelinePreviewChecker import PipelinePreviewChecker
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
class PipelineProcessor:
|
|
@@ -41,6 +43,10 @@ class PipelineProcessor:
|
|
|
41
43
|
self.worker_source_id = pipeline.worker_source_id
|
|
42
44
|
|
|
43
45
|
self.rtmp_streamer = None
|
|
46
|
+
self.rtmp_streaming_active = False
|
|
47
|
+
self.last_preview_check_time = 0
|
|
48
|
+
self.preview_check_interval = 5.0 # Check every 5 seconds
|
|
49
|
+
self.pipeline_repo = WorkerSourcePipelineRepository()
|
|
44
50
|
|
|
45
51
|
self.detection_processor_codes = [
|
|
46
52
|
PPEDetectionProcessor.code,
|
|
@@ -202,26 +208,42 @@ class PipelineProcessor:
|
|
|
202
208
|
logging.warning(f"Debug save failed: {e}")
|
|
203
209
|
self.debug_flag = False
|
|
204
210
|
|
|
205
|
-
#
|
|
206
|
-
|
|
207
|
-
if self.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
logging.info(f"🎬 RTMP streamer initialized for pipeline {pipeline_id}")
|
|
211
|
-
except Exception as e:
|
|
212
|
-
logging.error(f"❌ Failed to initialize RTMP streamer for pipeline {pipeline_id}: {e}")
|
|
213
|
-
self.rtmp_streamer = None
|
|
211
|
+
# Check if RTMP streaming should be active based on preview requests
|
|
212
|
+
current_time = time.time()
|
|
213
|
+
if current_time - self.last_preview_check_time >= self.preview_check_interval:
|
|
214
|
+
self._check_and_update_rtmp_streaming()
|
|
215
|
+
self.last_preview_check_time = current_time
|
|
214
216
|
|
|
215
|
-
if
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
217
|
+
# Push frame to RTMP stream if preview is active
|
|
218
|
+
if self.rtmp_streaming_active:
|
|
219
|
+
if self.rtmp_streamer is None:
|
|
220
|
+
try:
|
|
221
|
+
self.rtmp_streamer = RTMPStreamer(self.pipeline_id)
|
|
222
|
+
logging.info(f"🎬 RTMP streamer initialized for pipeline {pipeline_id} (preview requested)")
|
|
223
|
+
except Exception as e:
|
|
224
|
+
logging.error(f"❌ Failed to initialize RTMP streamer for pipeline {pipeline_id}: {e}")
|
|
225
|
+
self.rtmp_streamer = None
|
|
226
|
+
|
|
227
|
+
if self.rtmp_streamer:
|
|
228
|
+
try:
|
|
229
|
+
self.rtmp_streamer.push_frame(drawn_frame)
|
|
230
|
+
except Exception as e:
|
|
231
|
+
logging.error(f"❌ RTMP push error for pipeline {pipeline_id}: {e}")
|
|
232
|
+
if "initialization_failed" in str(e).lower():
|
|
233
|
+
try:
|
|
234
|
+
self.rtmp_streamer.stop_stream()
|
|
235
|
+
except Exception:
|
|
236
|
+
pass
|
|
237
|
+
self.rtmp_streamer = None
|
|
238
|
+
else:
|
|
239
|
+
# Stop RTMP streaming if preview is no longer active
|
|
240
|
+
if self.rtmp_streamer is not None:
|
|
241
|
+
try:
|
|
242
|
+
logging.info(f"🛑 Stopping RTMP streamer for pipeline {pipeline_id} (preview expired)")
|
|
243
|
+
self.rtmp_streamer.stop_stream()
|
|
244
|
+
except Exception as e:
|
|
245
|
+
logging.error(f"❌ Error stopping RTMP streamer: {e}")
|
|
246
|
+
finally:
|
|
225
247
|
self.rtmp_streamer = None
|
|
226
248
|
|
|
227
249
|
# feed detection worker with latest-only behavior
|
|
@@ -538,6 +560,33 @@ class PipelineProcessor:
|
|
|
538
560
|
self.consecutive_frame_failures = 0
|
|
539
561
|
self.last_successful_frame_time = time.time()
|
|
540
562
|
|
|
563
|
+
def _check_and_update_rtmp_streaming(self):
|
|
564
|
+
"""
|
|
565
|
+
Check if RTMP streaming should be active based on preview requests.
|
|
566
|
+
Updates the rtmp_streaming_active flag.
|
|
567
|
+
"""
|
|
568
|
+
try:
|
|
569
|
+
# Get fresh pipeline data from database
|
|
570
|
+
pipeline = self.pipeline_repo.get_worker_source_pipeline(self.pipeline_id)
|
|
571
|
+
|
|
572
|
+
if not pipeline:
|
|
573
|
+
logging.warning(f"⚠️ Pipeline {self.pipeline_id} not found in database")
|
|
574
|
+
self.rtmp_streaming_active = False
|
|
575
|
+
return
|
|
576
|
+
|
|
577
|
+
# Check if preview is active using the utility
|
|
578
|
+
should_stream = PipelinePreviewChecker.should_stream_rtmp(
|
|
579
|
+
pipeline.last_preview_request_at,
|
|
580
|
+
preview_window_seconds=300 # 5 minutes
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
self.rtmp_streaming_active = should_stream
|
|
584
|
+
|
|
585
|
+
except Exception as e:
|
|
586
|
+
logging.error(f"❌ Error checking preview status for pipeline {self.pipeline_id}: {e}")
|
|
587
|
+
# On error, disable streaming to be safe
|
|
588
|
+
self.rtmp_streaming_active = False
|
|
589
|
+
|
|
541
590
|
def reset_frame_failure_counters(self):
|
|
542
591
|
logging.info(f"🔄 Resetting frame failure counters for pipeline {self.pipeline_id}")
|
|
543
592
|
self.consecutive_frame_failures = 0
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
class PipelinePreviewChecker:
|
|
4
|
+
"""
|
|
5
|
+
Utility class to check if RTMP streaming should be enabled for a pipeline
|
|
6
|
+
based on the last preview request timestamp.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
@staticmethod
|
|
10
|
+
def should_stream_rtmp(last_preview_request_at, preview_window_seconds=300):
|
|
11
|
+
"""
|
|
12
|
+
Check if RTMP streaming should be enabled based on the last preview request.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
last_preview_request_at: DateTime object or None representing the last preview request
|
|
16
|
+
preview_window_seconds: Time window in seconds to keep streaming after a request (default: 300 = 5 minutes)
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
bool: True if streaming should be enabled, False otherwise
|
|
20
|
+
"""
|
|
21
|
+
if last_preview_request_at is None:
|
|
22
|
+
return False
|
|
23
|
+
|
|
24
|
+
# Calculate the time difference
|
|
25
|
+
current_time = datetime.utcnow()
|
|
26
|
+
time_since_request = current_time - last_preview_request_at
|
|
27
|
+
|
|
28
|
+
# Check if we're within the preview window
|
|
29
|
+
return time_since_request.total_seconds() <= preview_window_seconds
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def get_remaining_preview_time(last_preview_request_at, preview_window_seconds=300):
|
|
33
|
+
"""
|
|
34
|
+
Get the remaining time (in seconds) for the preview window.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
last_preview_request_at: DateTime object or None representing the last preview request
|
|
38
|
+
preview_window_seconds: Time window in seconds (default: 300 = 5 minutes)
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
int: Remaining seconds in the preview window, or 0 if expired/not requested
|
|
42
|
+
"""
|
|
43
|
+
if last_preview_request_at is None:
|
|
44
|
+
return 0
|
|
45
|
+
|
|
46
|
+
current_time = datetime.utcnow()
|
|
47
|
+
time_since_request = current_time - last_preview_request_at
|
|
48
|
+
remaining = preview_window_seconds - time_since_request.total_seconds()
|
|
49
|
+
|
|
50
|
+
return max(0, int(remaining))
|
{nedo_vision_worker_core-0.3.6.dist-info → nedo_vision_worker_core-0.3.7.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nedo-vision-worker-core
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
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,4 +1,4 @@
|
|
|
1
|
-
nedo_vision_worker_core/__init__.py,sha256=
|
|
1
|
+
nedo_vision_worker_core/__init__.py,sha256=PqquZ5-JOZg5UUcsfuxszP0e6O1jt9jItruqFR6Rekk,1924
|
|
2
2
|
nedo_vision_worker_core/cli.py,sha256=8YuKWsIgICUYXE_QtwyU3WzGhVjTWiAo5uzpFOmjNc8,5766
|
|
3
3
|
nedo_vision_worker_core/core_service.py,sha256=dnHNjbslOeyeWqHDFnk_yKdfTICYzLyRIcuZNwF0Zf4,11323
|
|
4
4
|
nedo_vision_worker_core/doctor.py,sha256=K_-hVV2-mdEefZ4Cfu5hMCiOxBiI1aXY8VtkkpK80Lc,10651
|
|
@@ -53,7 +53,7 @@ nedo_vision_worker_core/models/ppe_detection_label.py,sha256=qON7a0fuDv5cK8phGH0
|
|
|
53
53
|
nedo_vision_worker_core/models/restricted_area_violation.py,sha256=0enCi3tv15YMy3NaI6FwqhmLYHbbVX4nWTh46qKxrWc,829
|
|
54
54
|
nedo_vision_worker_core/models/user.py,sha256=SnLUz2nS7j17bIP-gElMEaR-jWdnNQ0fTpRminVKY60,294
|
|
55
55
|
nedo_vision_worker_core/models/worker_source.py,sha256=FB8irZ26LhCKNHBcpIIb5Mi3SoSNm9-q25VIkO5jQWg,793
|
|
56
|
-
nedo_vision_worker_core/models/worker_source_pipeline.py,sha256=
|
|
56
|
+
nedo_vision_worker_core/models/worker_source_pipeline.py,sha256=CGA_nz5wywsJcBPm-5kd0v_-h59f8Iu7uEeX3C91eT4,824
|
|
57
57
|
nedo_vision_worker_core/models/worker_source_pipeline_config.py,sha256=dGYTpcTFFu6pmGBufuWBHjv3Xs4RGAQwZn6jp6Ondvs,876
|
|
58
58
|
nedo_vision_worker_core/models/worker_source_pipeline_debug.py,sha256=6S7TkN37FrAT4VwsEB38DWSad7QfvNhsOGtSEK8D1Qs,594
|
|
59
59
|
nedo_vision_worker_core/models/worker_source_pipeline_detection.py,sha256=p6CJsiVCKprTYrNxJsiTB8njXdHkjZKVEyBceRVE6fY,560
|
|
@@ -61,7 +61,7 @@ nedo_vision_worker_core/pipeline/ModelManager.py,sha256=K7lmVOo-KL7bnWtyafilZs23
|
|
|
61
61
|
nedo_vision_worker_core/pipeline/PipelineConfigManager.py,sha256=X55i9GyXcW9ylO6cj2UMAZFSxxPViacL4H4DZl60CAY,1157
|
|
62
62
|
nedo_vision_worker_core/pipeline/PipelineManager.py,sha256=S3QxTcJjDhOY2O8x9c62kYXotgjV4enlCJLcziZEIh8,7589
|
|
63
63
|
nedo_vision_worker_core/pipeline/PipelinePrepocessor.py,sha256=cCiVSHHqsKCtKYURdYoEjHJX2GnT6zd8kQ6ZukjQ3V0,1271
|
|
64
|
-
nedo_vision_worker_core/pipeline/PipelineProcessor.py,sha256=
|
|
64
|
+
nedo_vision_worker_core/pipeline/PipelineProcessor.py,sha256=E3W9E1Ph_Qr6Gabdk3AUCtAIHw-r2-opJ0RuwOJlziI,29288
|
|
65
65
|
nedo_vision_worker_core/pipeline/PipelineSyncThread.py,sha256=2tIqheE2BG-DAEqUgq9i4blz0vQWmnYu8MgHPLJkg3g,8704
|
|
66
66
|
nedo_vision_worker_core/pipeline/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
|
67
67
|
nedo_vision_worker_core/preprocessing/ImageResizer.py,sha256=RvOazxe6dJQuiy0ZH4lIGbdFfiu0FLUVCHoMvxkDNT4,1324
|
|
@@ -94,11 +94,12 @@ nedo_vision_worker_core/util/DrawingUtils.py,sha256=sLptmzVaJakP_ZgbZsLL03RMH_9N
|
|
|
94
94
|
nedo_vision_worker_core/util/ModelReadinessChecker.py,sha256=ywHvt_d7UlY3DyFEJrO4Iyl0zx3SaLKb-Qab5l5Q8n4,6548
|
|
95
95
|
nedo_vision_worker_core/util/PersonAttributeMatcher.py,sha256=PhYTPYSF62Nfuc7dage03K6icw_bBBdpvXvnlzCbS30,2773
|
|
96
96
|
nedo_vision_worker_core/util/PersonRestrictedAreaMatcher.py,sha256=iuzCU32BQKaZ3dIy0QHNg2yoWJA-XhTRwwYqCvFdDgg,1711
|
|
97
|
+
nedo_vision_worker_core/util/PipelinePreviewChecker.py,sha256=XxlSMlrDlRrzfV8_Y--40Xfk5N7FjGgkKHth3KKCZzU,1963
|
|
97
98
|
nedo_vision_worker_core/util/PlatformDetector.py,sha256=GGL8UfeMQITR22EMYIRWnuOEnSqo7Dr5mb0PaFrl8AM,3006
|
|
98
99
|
nedo_vision_worker_core/util/TablePrinter.py,sha256=wzLGgb1GFMeIbAP6HmKcZD33j4D-IlyqlyeR7C5yD7w,1137
|
|
99
100
|
nedo_vision_worker_core/util/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
|
100
|
-
nedo_vision_worker_core-0.3.
|
|
101
|
-
nedo_vision_worker_core-0.3.
|
|
102
|
-
nedo_vision_worker_core-0.3.
|
|
103
|
-
nedo_vision_worker_core-0.3.
|
|
104
|
-
nedo_vision_worker_core-0.3.
|
|
101
|
+
nedo_vision_worker_core-0.3.7.dist-info/METADATA,sha256=fG5OjnALiAwUrLmyQXrQAu9FyvxiiVdsDqKrNSk2e68,14412
|
|
102
|
+
nedo_vision_worker_core-0.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
103
|
+
nedo_vision_worker_core-0.3.7.dist-info/entry_points.txt,sha256=pIPafsvPnBw-fpBKBmc1NQCQ6PQY3ad8mZ6mn8_p5FI,70
|
|
104
|
+
nedo_vision_worker_core-0.3.7.dist-info/top_level.txt,sha256=y8kusXjVYqtG8MSHYWTrk8bRrvjOrphKXYyzu943TTQ,24
|
|
105
|
+
nedo_vision_worker_core-0.3.7.dist-info/RECORD,,
|
|
File without changes
|
{nedo_vision_worker_core-0.3.6.dist-info → nedo_vision_worker_core-0.3.7.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{nedo_vision_worker_core-0.3.6.dist-info → nedo_vision_worker_core-0.3.7.dist-info}/top_level.txt
RENAMED
|
File without changes
|