nedo-vision-worker-core 0.3.0__tar.gz → 0.3.1__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.
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/PKG-INFO +1 -1
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/__init__.py +1 -1
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/cli.py +4 -56
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/pipeline/PipelineProcessor.py +248 -6
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/streams/VideoStream.py +62 -3
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core.egg-info/PKG-INFO +1 -1
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/MANIFEST.in +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/README.md +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/ai/FrameDrawer.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/ai/ImageDebugger.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/ai/VideoDebugger.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/ai/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/callbacks/DetectionCallbackManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/callbacks/DetectionCallbackTypes.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/callbacks/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/config/ConfigurationManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/config/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/core_service.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/database/DatabaseManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/database/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/detection/BaseDetector.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/detection/DetectionManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/detection/RFDETRDetector.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/detection/YOLODetector.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/detection/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/detection/detection_processing/DetectionProcessor.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/detection/detection_processing/HumanDetectionProcessor.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/detection/detection_processing/PPEDetectionProcessor.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/detection/detection_processing/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/doctor.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/blue/inner_corner.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/blue/inner_frame.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/blue/line.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/blue/top_left.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/blue/top_right.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/red/inner_corner.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/red/inner_frame.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/red/line.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/red/top_left.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/drawing_assets/red/top_right.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/boots-green.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/boots-red.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/gloves-green.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/gloves-red.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/goggles-green.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/goggles-red.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/helmet-green.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/helmet-red.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/mask-red.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/vest-green.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/icons/vest-red.png +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/ai_model.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/auth.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/config.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/dataset_source.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/logs.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/ppe_detection.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/ppe_detection_label.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/restricted_area_violation.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/user.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/worker_source.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/worker_source_pipeline.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/worker_source_pipeline_config.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/worker_source_pipeline_debug.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/models/worker_source_pipeline_detection.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/pipeline/PipelineConfigManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/pipeline/PipelineManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/pipeline/PipelinePrepocessor.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/pipeline/PipelineSyncThread.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/pipeline/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/preprocessing/ImageResizer.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/preprocessing/ImageRoi.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/preprocessing/Preprocessor.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/preprocessing/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/repositories/AIModelRepository.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/repositories/PPEDetectionRepository.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/repositories/RestrictedAreaRepository.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/repositories/WorkerSourcePipelineDebugRepository.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/repositories/WorkerSourcePipelineDetectionRepository.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/repositories/WorkerSourcePipelineRepository.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/repositories/WorkerSourceRepository.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/repositories/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/services/SharedVideoStreamServer.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/services/VideoSharingDaemon.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/services/VideoSharingDaemonManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/streams/RTMPStreamer.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/streams/SharedVideoDeviceManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/streams/StreamSyncThread.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/streams/VideoStreamManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/streams/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/tracker/SFSORT.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/tracker/TrackerManager.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/tracker/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/util/BoundingBoxMetrics.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/util/DrawingUtils.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/util/ModelReadinessChecker.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/util/PersonAttributeMatcher.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/util/PersonRestrictedAreaMatcher.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/util/TablePrinter.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/util/__init__.py +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core.egg-info/SOURCES.txt +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core.egg-info/dependency_links.txt +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core.egg-info/entry_points.txt +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core.egg-info/requires.txt +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core.egg-info/top_level.txt +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/pyproject.toml +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/requirements.txt +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/setup.cfg +0 -0
- {nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/setup.py +0 -0
|
@@ -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.1
|
|
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>
|
{nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/__init__.py
RENAMED
|
@@ -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.1"
|
|
11
11
|
__all__ = [
|
|
12
12
|
"CoreService",
|
|
13
13
|
"DetectionType",
|
{nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/cli.py
RENAMED
|
@@ -91,61 +91,15 @@ Detection Callbacks:
|
|
|
91
91
|
|
|
92
92
|
run_parser.add_argument(
|
|
93
93
|
"--rtmp-server",
|
|
94
|
-
default="rtmp://
|
|
95
|
-
help="RTMP server URL for video streaming (default: rtmp://
|
|
94
|
+
default="rtmp://live.vision.sindika.co.id:1935/live",
|
|
95
|
+
help="RTMP server URL for video streaming (default: rtmp://live.vision.sindika.co.id:1935/live)"
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
run_parser.add_argument(
|
|
99
|
-
"--
|
|
100
|
-
action="store_true",
|
|
101
|
-
default=True,
|
|
102
|
-
help="Enable automatic video sharing daemon management (default: True)"
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
run_parser.add_argument(
|
|
106
|
-
"--disable-video-sharing-daemon",
|
|
99
|
+
"--disable_video_sharing_daemon",
|
|
107
100
|
action="store_true",
|
|
108
101
|
default=False,
|
|
109
|
-
help="Disable automatic video sharing daemon management"
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
# Add legacy arguments for backward compatibility (when no subcommand is used)
|
|
113
|
-
parser.add_argument(
|
|
114
|
-
"--drawing-assets",
|
|
115
|
-
help="(Legacy) Path to drawing assets directory (optional, uses bundled assets by default)"
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
parser.add_argument(
|
|
119
|
-
"--log-level",
|
|
120
|
-
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
|
121
|
-
default="INFO",
|
|
122
|
-
help="(Legacy) Logging level (default: INFO)"
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
parser.add_argument(
|
|
126
|
-
"--storage-path",
|
|
127
|
-
default="data",
|
|
128
|
-
help="(Legacy) Storage path for databases and files (default: data)"
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
parser.add_argument(
|
|
132
|
-
"--rtmp-server",
|
|
133
|
-
default="rtmp://localhost:1935/live",
|
|
134
|
-
help="(Legacy) RTMP server URL for video streaming (default: rtmp://localhost:1935/live)"
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
parser.add_argument(
|
|
138
|
-
"--enable-video-sharing-daemon",
|
|
139
|
-
action="store_true",
|
|
140
|
-
default=True,
|
|
141
|
-
help="(Legacy) Enable automatic video sharing daemon management (default: True)"
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
parser.add_argument(
|
|
145
|
-
"--disable-video-sharing-daemon",
|
|
146
|
-
action="store_true",
|
|
147
|
-
default=False,
|
|
148
|
-
help="(Legacy) Disable automatic video sharing daemon management"
|
|
102
|
+
help="Disable automatic video sharing daemon management (default: False)"
|
|
149
103
|
)
|
|
150
104
|
|
|
151
105
|
parser.add_argument(
|
|
@@ -161,11 +115,7 @@ Detection Callbacks:
|
|
|
161
115
|
run_core_service(args)
|
|
162
116
|
elif args.command == 'doctor':
|
|
163
117
|
run_doctor()
|
|
164
|
-
elif hasattr(args, 'drawing_assets') and args.drawing_assets is not None: # Legacy mode - if any arguments are provided without subcommand
|
|
165
|
-
print("⚠️ Warning: Using legacy command format. Consider using 'nedo-core run --drawing-assets ...' instead.")
|
|
166
|
-
run_core_service(args)
|
|
167
118
|
else:
|
|
168
|
-
# If no subcommand provided, show help
|
|
169
119
|
parser.print_help()
|
|
170
120
|
sys.exit(1)
|
|
171
121
|
|
|
@@ -197,8 +147,6 @@ def run_core_service(args):
|
|
|
197
147
|
enable_daemon = True # Default
|
|
198
148
|
if hasattr(args, 'disable_video_sharing_daemon') and args.disable_video_sharing_daemon:
|
|
199
149
|
enable_daemon = False
|
|
200
|
-
elif hasattr(args, 'enable_video_sharing_daemon'):
|
|
201
|
-
enable_daemon = args.enable_video_sharing_daemon
|
|
202
150
|
|
|
203
151
|
# Create and start the core service
|
|
204
152
|
service = CoreService(
|
|
@@ -54,6 +54,17 @@ class PipelineProcessor:
|
|
|
54
54
|
self.debug_flag = False
|
|
55
55
|
self.debug_repo = WorkerSourcePipelineDebugRepository()
|
|
56
56
|
self.detection_repo = WorkerSourcePipelineDetectionRepository()
|
|
57
|
+
|
|
58
|
+
# Frame recovery mechanism
|
|
59
|
+
self.consecutive_frame_failures = 0
|
|
60
|
+
self.max_consecutive_failures = 150 # 1.5 seconds at 0.01s intervals
|
|
61
|
+
self.last_successful_frame_time = time.time()
|
|
62
|
+
self.stream_recovery_timeout = 30.0 # 30 seconds timeout for stream recovery
|
|
63
|
+
|
|
64
|
+
# HEVC error tracking
|
|
65
|
+
self.hevc_error_count = 0
|
|
66
|
+
self.last_hevc_recovery = 0
|
|
67
|
+
self.hevc_recovery_cooldown = 30.0 # 30 seconds between HEVC recovery attempts
|
|
57
68
|
|
|
58
69
|
def load_model(self, model):
|
|
59
70
|
"""
|
|
@@ -113,6 +124,10 @@ class PipelineProcessor:
|
|
|
113
124
|
self.preprocessor.update(self.config_manager)
|
|
114
125
|
self.detection_interval = self._get_detection_interval()
|
|
115
126
|
self._update_detection_processor()
|
|
127
|
+
|
|
128
|
+
# Reset frame failure counters on config update
|
|
129
|
+
self.consecutive_frame_failures = 0
|
|
130
|
+
self.last_successful_frame_time = time.time()
|
|
116
131
|
|
|
117
132
|
ai_model = self.detection_manager.model_metadata
|
|
118
133
|
|
|
@@ -142,6 +157,10 @@ class PipelineProcessor:
|
|
|
142
157
|
logging.info(f"🎯 Running pipeline processing for pipeline {pipeline_id} | Source: {worker_source_id}")
|
|
143
158
|
|
|
144
159
|
self._update_config()
|
|
160
|
+
|
|
161
|
+
# Reset failure counters at start
|
|
162
|
+
self.consecutive_frame_failures = 0
|
|
163
|
+
self.last_successful_frame_time = time.time()
|
|
145
164
|
|
|
146
165
|
initial_frame = self._wait_for_frame(video_manager)
|
|
147
166
|
if initial_frame is None:
|
|
@@ -163,14 +182,14 @@ class PipelineProcessor:
|
|
|
163
182
|
frame = video_manager.get_frame(worker_source_id)
|
|
164
183
|
|
|
165
184
|
if frame is None:
|
|
166
|
-
|
|
167
|
-
# Check if stream was removed
|
|
168
|
-
if not video_manager.has_stream(worker_source_id):
|
|
169
|
-
logging.info(f"🛑 Stream {worker_source_id} was removed, stopping pipeline")
|
|
185
|
+
if not self._handle_frame_failure(video_manager, worker_source_id):
|
|
170
186
|
break
|
|
171
|
-
time.sleep(0.01)
|
|
172
187
|
continue
|
|
173
188
|
|
|
189
|
+
# Reset failure counters on successful frame
|
|
190
|
+
self.consecutive_frame_failures = 0
|
|
191
|
+
self.last_successful_frame_time = time.time()
|
|
192
|
+
|
|
174
193
|
self.frame_counter += 1
|
|
175
194
|
|
|
176
195
|
self.frame_drawer.draw_polygons(frame)
|
|
@@ -305,15 +324,200 @@ class PipelineProcessor:
|
|
|
305
324
|
|
|
306
325
|
def _wait_for_frame(self, video_manager, max_retries=10, sleep_time=3):
|
|
307
326
|
"""Waits until a frame is available from the video source."""
|
|
327
|
+
logging.info(f"⏳ Waiting for initial frame from {self.worker_source_id}...")
|
|
328
|
+
|
|
308
329
|
for retry_count in range(max_retries):
|
|
309
330
|
frame = video_manager.get_frame(self.worker_source_id)
|
|
310
331
|
if frame is not None:
|
|
332
|
+
logging.info(f"✅ Initial frame received from {self.worker_source_id}")
|
|
311
333
|
return frame
|
|
334
|
+
|
|
335
|
+
# Check if stream exists
|
|
336
|
+
if not video_manager.has_stream(self.worker_source_id):
|
|
337
|
+
logging.error(f"❌ Stream {self.worker_source_id} not found in video manager")
|
|
338
|
+
return None
|
|
339
|
+
|
|
312
340
|
logging.warning(f"⚠️ Waiting for video stream {self.worker_source_id} (Attempt {retry_count + 1}/{max_retries})...")
|
|
341
|
+
|
|
342
|
+
# Log stream diagnostics on later attempts
|
|
343
|
+
if retry_count >= 3:
|
|
344
|
+
self._log_stream_diagnostics(video_manager, self.worker_source_id)
|
|
345
|
+
|
|
313
346
|
time.sleep(sleep_time)
|
|
314
347
|
|
|
348
|
+
logging.error(f"❌ Failed to get initial frame from {self.worker_source_id} after {max_retries} attempts")
|
|
315
349
|
return None
|
|
316
350
|
|
|
351
|
+
def _handle_frame_failure(self, video_manager, worker_source_id):
|
|
352
|
+
"""
|
|
353
|
+
Handle frame retrieval failures with progressive backoff and recovery attempts.
|
|
354
|
+
Returns False if pipeline should stop, True to continue.
|
|
355
|
+
"""
|
|
356
|
+
self.consecutive_frame_failures += 1
|
|
357
|
+
|
|
358
|
+
# Check if stream was removed
|
|
359
|
+
if not video_manager.has_stream(worker_source_id):
|
|
360
|
+
logging.info(f"🛑 Stream {worker_source_id} was removed, stopping pipeline")
|
|
361
|
+
return False
|
|
362
|
+
|
|
363
|
+
# Check for stream recovery timeout
|
|
364
|
+
time_since_last_frame = time.time() - self.last_successful_frame_time
|
|
365
|
+
if time_since_last_frame > self.stream_recovery_timeout:
|
|
366
|
+
logging.error(f"❌ Stream {worker_source_id} recovery timeout ({self.stream_recovery_timeout}s). Stopping pipeline.")
|
|
367
|
+
return False
|
|
368
|
+
|
|
369
|
+
# Progressive logging and backoff
|
|
370
|
+
if self.consecutive_frame_failures <= 10:
|
|
371
|
+
# First 10 failures: minimal logging, fast retry
|
|
372
|
+
if self.consecutive_frame_failures % 5 == 1: # Log every 5th failure
|
|
373
|
+
logging.debug(f"⚠️ No frame available for {worker_source_id} (attempt {self.consecutive_frame_failures})")
|
|
374
|
+
time.sleep(0.01)
|
|
375
|
+
elif self.consecutive_frame_failures <= 50:
|
|
376
|
+
# 11-50 failures: moderate logging, slightly longer wait
|
|
377
|
+
if self.consecutive_frame_failures % 10 == 1: # Log every 10th failure
|
|
378
|
+
logging.warning(f"⚠️ No frame available for {worker_source_id} (attempt {self.consecutive_frame_failures}). Stream may be reconnecting...")
|
|
379
|
+
time.sleep(0.05)
|
|
380
|
+
elif self.consecutive_frame_failures <= self.max_consecutive_failures:
|
|
381
|
+
# 51-150 failures: more frequent logging, longer wait
|
|
382
|
+
if self.consecutive_frame_failures % 20 == 1: # Log every 20th failure
|
|
383
|
+
logging.warning(f"⚠️ Persistent frame issues for {worker_source_id} (attempt {self.consecutive_frame_failures}). Checking stream health...")
|
|
384
|
+
self._log_stream_diagnostics(video_manager, worker_source_id)
|
|
385
|
+
|
|
386
|
+
# Attempt HEVC recovery on severe persistent failures (every 60 failures to avoid too frequent reconnections)
|
|
387
|
+
if self.consecutive_frame_failures % 60 == 1:
|
|
388
|
+
# Check if we should attempt HEVC recovery based on error patterns and cooldown
|
|
389
|
+
if self._should_attempt_hevc_recovery(video_manager, worker_source_id):
|
|
390
|
+
logging.info(f"🔧 Attempting HEVC-specific recovery for persistent frame failures...")
|
|
391
|
+
recovery_success = self._handle_hevc_recovery(video_manager, worker_source_id)
|
|
392
|
+
if recovery_success:
|
|
393
|
+
logging.info(f"✅ HEVC recovery successful, continuing pipeline...")
|
|
394
|
+
return True # Continue processing after successful recovery
|
|
395
|
+
|
|
396
|
+
time.sleep(0.1)
|
|
397
|
+
else:
|
|
398
|
+
# Over max failures: critical logging and stop
|
|
399
|
+
logging.error(f"❌ Too many consecutive frame failures for {worker_source_id} ({self.consecutive_frame_failures}). Stopping pipeline.")
|
|
400
|
+
self._log_stream_diagnostics(video_manager, worker_source_id)
|
|
401
|
+
return False
|
|
402
|
+
|
|
403
|
+
return True
|
|
404
|
+
|
|
405
|
+
def _log_stream_diagnostics(self, video_manager, worker_source_id):
|
|
406
|
+
"""Log diagnostic information about the stream state."""
|
|
407
|
+
try:
|
|
408
|
+
stream_url = video_manager.get_stream_url(worker_source_id)
|
|
409
|
+
is_file = video_manager.is_video_file(worker_source_id)
|
|
410
|
+
|
|
411
|
+
# Get stream object for more detailed diagnostics
|
|
412
|
+
if hasattr(video_manager, 'streams') and worker_source_id in video_manager.streams:
|
|
413
|
+
stream = video_manager.streams[worker_source_id]
|
|
414
|
+
state = stream.get_state() if hasattr(stream, 'get_state') else "unknown"
|
|
415
|
+
is_connected = stream.is_connected() if hasattr(stream, 'is_connected') else "unknown"
|
|
416
|
+
|
|
417
|
+
logging.info(f"📊 Stream diagnostics for {worker_source_id}:")
|
|
418
|
+
logging.info(f" URL: {stream_url}")
|
|
419
|
+
logging.info(f" Type: {'Video file' if is_file else 'Live stream'}")
|
|
420
|
+
logging.info(f" State: {state}")
|
|
421
|
+
logging.info(f" Connected: {is_connected}")
|
|
422
|
+
logging.info(f" Time since last frame: {time.time() - self.last_successful_frame_time:.1f}s")
|
|
423
|
+
|
|
424
|
+
# Check for HEVC/codec specific issues
|
|
425
|
+
if hasattr(stream, 'get_codec_info'):
|
|
426
|
+
codec_info = stream.get_codec_info()
|
|
427
|
+
if codec_info:
|
|
428
|
+
logging.info(f" Codec: {codec_info}")
|
|
429
|
+
if 'hevc' in str(codec_info).lower() or 'h265' in str(codec_info).lower():
|
|
430
|
+
logging.warning(f" ⚠️ HEVC stream detected - may experience QP delta or POC reference errors")
|
|
431
|
+
|
|
432
|
+
# Log recent error patterns if available
|
|
433
|
+
if hasattr(stream, 'get_recent_errors'):
|
|
434
|
+
recent_errors = stream.get_recent_errors()
|
|
435
|
+
if recent_errors:
|
|
436
|
+
hevc_errors = [err for err in recent_errors if 'cu_qp_delta' in str(err.get('error', '')) or 'Could not find ref with POC' in str(err.get('error', ''))]
|
|
437
|
+
if hevc_errors:
|
|
438
|
+
logging.warning(f" 🔥 Recent HEVC errors detected: {len(hevc_errors)} codec-related errors")
|
|
439
|
+
self.hevc_error_count += len(hevc_errors)
|
|
440
|
+
|
|
441
|
+
# Log sample of recent HEVC errors for debugging
|
|
442
|
+
for i, err in enumerate(hevc_errors[-3:]): # Show last 3 errors
|
|
443
|
+
logging.warning(f" 🔥 HEVC Error {i+1}: {err.get('error', '')[:100]}...")
|
|
444
|
+
else:
|
|
445
|
+
logging.info(f"📊 Stream {worker_source_id} not found in regular streams, checking direct device streams...")
|
|
446
|
+
|
|
447
|
+
except Exception as e:
|
|
448
|
+
logging.error(f"Error getting stream diagnostics: {e}")
|
|
449
|
+
|
|
450
|
+
def _should_attempt_hevc_recovery(self, video_manager, worker_source_id) -> bool:
|
|
451
|
+
"""
|
|
452
|
+
Determine if HEVC recovery should be attempted based on error patterns and cooldown.
|
|
453
|
+
"""
|
|
454
|
+
current_time = time.time()
|
|
455
|
+
|
|
456
|
+
# Check cooldown period
|
|
457
|
+
if current_time - self.last_hevc_recovery < self.hevc_recovery_cooldown:
|
|
458
|
+
logging.debug(f"HEVC recovery on cooldown ({current_time - self.last_hevc_recovery:.1f}s elapsed)")
|
|
459
|
+
return False
|
|
460
|
+
|
|
461
|
+
# Check if stream has HEVC-related errors
|
|
462
|
+
if hasattr(video_manager, 'streams') and worker_source_id in video_manager.streams:
|
|
463
|
+
stream = video_manager.streams[worker_source_id]
|
|
464
|
+
if hasattr(stream, 'get_recent_errors'):
|
|
465
|
+
recent_errors = stream.get_recent_errors(max_age_seconds=60) # Last minute
|
|
466
|
+
hevc_errors = [err for err in recent_errors if
|
|
467
|
+
'cu_qp_delta' in str(err.get('error', '')) or
|
|
468
|
+
'Could not find ref with POC' in str(err.get('error', ''))]
|
|
469
|
+
|
|
470
|
+
if len(hevc_errors) >= 3: # Threshold for HEVC errors
|
|
471
|
+
logging.info(f"HEVC recovery warranted: {len(hevc_errors)} HEVC errors in last minute")
|
|
472
|
+
return True
|
|
473
|
+
|
|
474
|
+
# Check if we have accumulated enough general HEVC errors
|
|
475
|
+
if self.hevc_error_count >= 5:
|
|
476
|
+
logging.info(f"HEVC recovery warranted: {self.hevc_error_count} total HEVC errors detected")
|
|
477
|
+
return True
|
|
478
|
+
|
|
479
|
+
return False
|
|
480
|
+
|
|
481
|
+
def _handle_hevc_recovery(self, video_manager, worker_source_id):
|
|
482
|
+
"""
|
|
483
|
+
Handle HEVC-specific recovery strategies for codec errors.
|
|
484
|
+
This method attempts to recover from common HEVC issues like QP delta and POC reference errors.
|
|
485
|
+
"""
|
|
486
|
+
try:
|
|
487
|
+
self.last_hevc_recovery = time.time() # Update recovery timestamp
|
|
488
|
+
logging.info(f"🔧 Attempting HEVC stream recovery for {worker_source_id}")
|
|
489
|
+
|
|
490
|
+
# Get the stream URL for recreation
|
|
491
|
+
stream_url = video_manager.get_stream_url(worker_source_id)
|
|
492
|
+
if not stream_url:
|
|
493
|
+
logging.error(f" Cannot get stream URL for {worker_source_id}")
|
|
494
|
+
return False
|
|
495
|
+
|
|
496
|
+
# Strategy 1: Remove and re-add the stream to reset decoder state
|
|
497
|
+
logging.info(f" Recreating stream {worker_source_id} to reset decoder state...")
|
|
498
|
+
video_manager.remove_stream(worker_source_id)
|
|
499
|
+
time.sleep(1.0) # Give time for cleanup
|
|
500
|
+
|
|
501
|
+
# Re-add the stream
|
|
502
|
+
video_manager.add_stream(worker_source_id, stream_url)
|
|
503
|
+
time.sleep(2.0) # Give time for stream to initialize
|
|
504
|
+
|
|
505
|
+
# Strategy 2: Check if stream was successfully recreated
|
|
506
|
+
if not video_manager.has_stream(worker_source_id):
|
|
507
|
+
logging.error(f" Failed to recreate stream {worker_source_id}")
|
|
508
|
+
return False
|
|
509
|
+
|
|
510
|
+
# Strategy 3: Reset failure counters and error counts after recovery attempt
|
|
511
|
+
self.reset_frame_failure_counters()
|
|
512
|
+
self.hevc_error_count = 0 # Reset HEVC error counter
|
|
513
|
+
|
|
514
|
+
logging.info(f"✅ HEVC recovery attempt completed for {worker_source_id}")
|
|
515
|
+
return True
|
|
516
|
+
|
|
517
|
+
except Exception as e:
|
|
518
|
+
logging.error(f"❌ HEVC recovery failed for {worker_source_id}: {e}")
|
|
519
|
+
return False
|
|
520
|
+
|
|
317
521
|
def stop(self):
|
|
318
522
|
"""Stops the Pipeline processor and cleans up resources."""
|
|
319
523
|
if not self.running: # Prevent multiple stops
|
|
@@ -378,4 +582,42 @@ class PipelineProcessor:
|
|
|
378
582
|
|
|
379
583
|
def enable_debug(self):
|
|
380
584
|
"""Enable debug mode for this pipeline."""
|
|
381
|
-
self.debug_flag = True
|
|
585
|
+
self.debug_flag = True
|
|
586
|
+
# Reset failure counters when debug is enabled as it may help with recovery
|
|
587
|
+
self.consecutive_frame_failures = 0
|
|
588
|
+
self.last_successful_frame_time = time.time()
|
|
589
|
+
|
|
590
|
+
def reset_frame_failure_counters(self):
|
|
591
|
+
"""Reset frame failure counters. Can be called externally to help with recovery."""
|
|
592
|
+
logging.info(f"🔄 Resetting frame failure counters for pipeline {self.pipeline_id}")
|
|
593
|
+
self.consecutive_frame_failures = 0
|
|
594
|
+
self.last_successful_frame_time = time.time()
|
|
595
|
+
self.hevc_error_count = 0 # Also reset HEVC error count
|
|
596
|
+
|
|
597
|
+
def get_hevc_diagnostics(self, video_manager) -> dict:
|
|
598
|
+
"""Get HEVC-specific diagnostics for the pipeline."""
|
|
599
|
+
diagnostics = {
|
|
600
|
+
'hevc_error_count': self.hevc_error_count,
|
|
601
|
+
'last_hevc_recovery': self.last_hevc_recovery,
|
|
602
|
+
'time_since_last_recovery': time.time() - self.last_hevc_recovery,
|
|
603
|
+
'recovery_cooldown_remaining': max(0, self.hevc_recovery_cooldown - (time.time() - self.last_hevc_recovery)),
|
|
604
|
+
'consecutive_failures': self.consecutive_frame_failures,
|
|
605
|
+
'time_since_last_frame': time.time() - self.last_successful_frame_time,
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
# Add stream-specific HEVC information
|
|
609
|
+
if hasattr(video_manager, 'streams') and self.worker_source_id in video_manager.streams:
|
|
610
|
+
stream = video_manager.streams[self.worker_source_id]
|
|
611
|
+
|
|
612
|
+
if hasattr(stream, 'get_codec_info'):
|
|
613
|
+
diagnostics['codec'] = stream.get_codec_info()
|
|
614
|
+
|
|
615
|
+
if hasattr(stream, 'get_recent_errors'):
|
|
616
|
+
recent_errors = stream.get_recent_errors(max_age_seconds=300) # Last 5 minutes
|
|
617
|
+
hevc_errors = [err for err in recent_errors if
|
|
618
|
+
'cu_qp_delta' in str(err.get('error', '')) or
|
|
619
|
+
'Could not find ref with POC' in str(err.get('error', ''))]
|
|
620
|
+
diagnostics['recent_hevc_errors'] = len(hevc_errors)
|
|
621
|
+
diagnostics['total_recent_errors'] = len(recent_errors)
|
|
622
|
+
|
|
623
|
+
return diagnostics
|
|
@@ -50,6 +50,11 @@ class VideoStream(threading.Thread):
|
|
|
50
50
|
|
|
51
51
|
self.is_file = self._is_file_source()
|
|
52
52
|
|
|
53
|
+
# Error tracking for diagnostics
|
|
54
|
+
self._recent_errors = []
|
|
55
|
+
self._max_error_history = 50
|
|
56
|
+
self._codec_info = None
|
|
57
|
+
|
|
53
58
|
def _is_file_source(self) -> bool:
|
|
54
59
|
"""Check if source is a file path."""
|
|
55
60
|
if isinstance(self.source, int):
|
|
@@ -90,6 +95,32 @@ class VideoStream(threading.Thread):
|
|
|
90
95
|
"""Configure capture properties and determine FPS."""
|
|
91
96
|
detected_fps = self.capture.get(cv2.CAP_PROP_FPS)
|
|
92
97
|
|
|
98
|
+
# Configure error-resilient settings for video streams
|
|
99
|
+
if not self.is_file:
|
|
100
|
+
try:
|
|
101
|
+
# Set buffer size to reduce latency and handle corrupted frames better
|
|
102
|
+
self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
|
103
|
+
|
|
104
|
+
# Set codec-specific properties for better error handling
|
|
105
|
+
# These help with HEVC streams that have QP delta and POC reference errors
|
|
106
|
+
if hasattr(cv2, 'CAP_PROP_FOURCC'):
|
|
107
|
+
# Try to get current codec
|
|
108
|
+
fourcc = self.capture.get(cv2.CAP_PROP_FOURCC)
|
|
109
|
+
codec_str = "".join([chr((int(fourcc) >> 8 * i) & 0xFF) for i in range(4)])
|
|
110
|
+
|
|
111
|
+
# Log codec information for debugging
|
|
112
|
+
logging.info(f"Stream codec detected: {codec_str} (fourcc: {int(fourcc)})")
|
|
113
|
+
self._codec_info = codec_str
|
|
114
|
+
|
|
115
|
+
# For HEVC streams, we can't change the codec but we can optimize buffering
|
|
116
|
+
if 'hevc' in codec_str.lower() or 'h265' in codec_str.lower():
|
|
117
|
+
logging.info("HEVC stream detected - applying error-resilient settings")
|
|
118
|
+
# Reduce buffer to minimize impact of corrupted frames
|
|
119
|
+
self.capture.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
|
120
|
+
|
|
121
|
+
except Exception as e:
|
|
122
|
+
logging.warning(f"Could not configure capture properties: {e}")
|
|
123
|
+
|
|
93
124
|
if self.target_fps:
|
|
94
125
|
self.fps = self.target_fps
|
|
95
126
|
if hasattr(cv2, 'CAP_PROP_FPS'):
|
|
@@ -205,13 +236,17 @@ class VideoStream(threading.Thread):
|
|
|
205
236
|
break
|
|
206
237
|
|
|
207
238
|
except cv2.error as e:
|
|
208
|
-
|
|
239
|
+
error_msg = f"OpenCV error: {e}"
|
|
240
|
+
logging.error(error_msg)
|
|
241
|
+
self._add_error_to_history(error_msg)
|
|
209
242
|
self._cleanup_capture()
|
|
210
243
|
if not self._sleep_interruptible(1.0):
|
|
211
244
|
break
|
|
212
245
|
|
|
213
246
|
except Exception as e:
|
|
214
|
-
|
|
247
|
+
error_msg = f"Unexpected error: {e}"
|
|
248
|
+
logging.error(error_msg, exc_info=True)
|
|
249
|
+
self._add_error_to_history(error_msg)
|
|
215
250
|
if not self._sleep_interruptible(self.reconnect_interval):
|
|
216
251
|
break
|
|
217
252
|
|
|
@@ -283,4 +318,28 @@ class VideoStream(threading.Thread):
|
|
|
283
318
|
|
|
284
319
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
285
320
|
"""Context manager exit."""
|
|
286
|
-
self.stop()
|
|
321
|
+
self.stop()
|
|
322
|
+
|
|
323
|
+
def _add_error_to_history(self, error_msg: str):
|
|
324
|
+
"""Add error to recent error history for diagnostics."""
|
|
325
|
+
with self._lock:
|
|
326
|
+
self._recent_errors.append({
|
|
327
|
+
'timestamp': time.time(),
|
|
328
|
+
'error': error_msg
|
|
329
|
+
})
|
|
330
|
+
# Keep only recent errors
|
|
331
|
+
if len(self._recent_errors) > self._max_error_history:
|
|
332
|
+
self._recent_errors = self._recent_errors[-self._max_error_history:]
|
|
333
|
+
|
|
334
|
+
def get_recent_errors(self, max_age_seconds: float = 300) -> list:
|
|
335
|
+
"""Get recent errors within the specified time window."""
|
|
336
|
+
current_time = time.time()
|
|
337
|
+
with self._lock:
|
|
338
|
+
return [
|
|
339
|
+
err for err in self._recent_errors
|
|
340
|
+
if current_time - err['timestamp'] <= max_age_seconds
|
|
341
|
+
]
|
|
342
|
+
|
|
343
|
+
def get_codec_info(self) -> Optional[str]:
|
|
344
|
+
"""Get codec information for the stream."""
|
|
345
|
+
return self._codec_info
|
|
@@ -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.1
|
|
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>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nedo_vision_worker_core-0.3.0 → nedo_vision_worker_core-0.3.1}/nedo_vision_worker_core/doctor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|