nomadicml 0.0.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 NomadicML
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include LICENSE
2
+ include README.md
3
+ include requirements.txt
4
+ recursive-include examples *.py
@@ -0,0 +1,219 @@
1
+ Metadata-Version: 2.1
2
+ Name: nomadicml
3
+ Version: 0.0.1
4
+ Summary: Python SDK for NomadicML's DriveMonitor API
5
+ Author: NomadicML Inc
6
+ Author-email: info@nomadicml.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.8
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+ Provides-Extra: dev
20
+ License-File: LICENSE
21
+
22
+ # NomadicML Python SDK
23
+
24
+ A Python client library for the NomadicML DriveMonitor API, allowing you to upload and analyze driving videos programmatically.
25
+
26
+ ## Installation
27
+
28
+ ### From PyPI (for users)
29
+
30
+ ```bash
31
+ pip install nomadicml
32
+ ```
33
+
34
+ ### For Development (from source)
35
+
36
+ To install the package in development mode, where changes to the code will be immediately reflected without reinstallation:
37
+
38
+ ```bash
39
+ # Clone the repository
40
+ git clone https://github.com/nomadic-ml/drivemonitor.git
41
+ cd sdk
42
+
43
+ # For development: Install in editable mode
44
+ pip install -e .
45
+ ```
46
+
47
+ With this installation, any changes you make to the code will be immediately available when you import the package.
48
+
49
+ ## Quick Start
50
+
51
+ ```python
52
+ from nomadicml import NomadicML
53
+
54
+ # Initialize the client with your API key
55
+ client = NomadicML(api_key="your_api_key")
56
+
57
+ # Upload a video and analyze it in one step
58
+ result = client.video.upload_and_analyze("path/to/your/video.mp4")
59
+
60
+ # Print the detected events
61
+ for event in result["events"]:
62
+ print(f"Event: {event['type']} at {event['time']}s - {event['description']}")
63
+ #For a batch upload
64
+
65
+ videos_list = [.....]#list of video paths
66
+ batch_results = client.video.upload_and_analyze_videos(videos_list, wait_for_completion=False)
67
+
68
+
69
+ video_ids = [
70
+ res.get("video_id")
71
+ for res in batch_results
72
+ if res # safety for None
73
+ ]
74
+
75
+
76
+ full_results = client.video.wait_for_analyses(video_ids)
77
+
78
+ ```
79
+
80
+ ## Authentication
81
+
82
+ You need an API key to use the NomadicML API. You can get one by:
83
+
84
+ 1. Log in to your DriveMonitor account
85
+ 2. Go to Profile > API Key
86
+ 3. Generate a new API key
87
+
88
+ Then use this key when initializing the client:
89
+
90
+ ```python
91
+ client = NomadicML(api_key="your_api_key")
92
+ ```
93
+
94
+ ## Video Upload and Analysis
95
+
96
+ ### Upload a video
97
+
98
+ ```python
99
+ # Upload a local video file
100
+ result = client.video.upload_video(
101
+ source="file",
102
+ file_path="path/to/video.mp4"
103
+ )
104
+
105
+ # Or upload from YouTube
106
+ result = client.video.upload_video(
107
+ source="youtube",
108
+ youtube_url="https://www.youtube.com/watch?v=VIDEO_ID"
109
+ )
110
+
111
+ # Get the video ID from the response
112
+ video_id = result["video_id"]
113
+ ```
114
+
115
+ ### Analyze a video
116
+
117
+ ```python
118
+ # Start analysis
119
+ client.video.analyze_video(video_id)
120
+
121
+ # Wait for analysis to complete
122
+ status = client.video.wait_for_analysis(video_id)
123
+
124
+ # Get analysis results
125
+ analysis = client.video.get_video_analysis(video_id)
126
+
127
+ # Get detected events
128
+ events = client.video.get_video_events(video_id)
129
+ ```
130
+
131
+ ### Upload and analyze in one step
132
+
133
+ ```python
134
+ # Upload and analyze a video, waiting for results
135
+ analysis = client.video.upload_and_analyze("path/to/video.mp4")
136
+
137
+ # Or just start the process without waiting
138
+ result = client.video.upload_and_analyze("path/to/video.mp4", wait_for_completion=False)
139
+ ```
140
+
141
+ ## Advanced Usage
142
+
143
+ ### Filter events by severity or type
144
+
145
+ ```python
146
+ # Get only high severity events
147
+ high_severity_events = client.video.get_video_events(
148
+ video_id=video_id,
149
+ severity="high"
150
+ )
151
+
152
+ # Get only traffic violation events
153
+ traffic_violations = client.video.get_video_events(
154
+ video_id=video_id,
155
+ event_type="Traffic Violation"
156
+ )
157
+ ```
158
+
159
+ ### Custom timeout and polling interval
160
+
161
+ ```python
162
+ # Wait for analysis with a custom timeout and polling interval
163
+ client.video.wait_for_analysis(
164
+ video_id=video_id,
165
+ timeout=1200, # 20 minutes
166
+ poll_interval=10 # Check every 10 seconds
167
+ )
168
+ ```
169
+
170
+ ### Custom API endpoint
171
+
172
+ If you're using a custom deployment of the DriveMonitor backend:
173
+
174
+ ```python
175
+ # Connect to a local or custom deployment
176
+ client = NomadicML(
177
+ api_key="your_api_key",
178
+ base_url="http://localhost:8099"
179
+ )
180
+ ```
181
+
182
+ ## Error Handling
183
+
184
+ The SDK provides specific exceptions for different error types:
185
+
186
+ ```python
187
+ from nomadicml import NomadicMLError, AuthenticationError, VideoUploadError
188
+
189
+ try:
190
+ client.video.upload_and_analyze("path/to/video.mp4")
191
+ except AuthenticationError:
192
+ print("API key is invalid or expired")
193
+ except VideoUploadError as e:
194
+ print(f"Failed to upload video: {e}")
195
+ except NomadicMLError as e:
196
+ print(f"An error occurred: {e}")
197
+ ```
198
+
199
+ ## Development
200
+
201
+ ### Setup
202
+
203
+ Clone the repository and install development dependencies:
204
+
205
+ ```bash
206
+ git clone https://github.com/nomadicml/nomadicml-python.git
207
+ cd nomadicml-python
208
+ pip install -e ".[dev]"
209
+ ```
210
+
211
+ ### Running tests
212
+
213
+ ```bash
214
+ pytest
215
+ ```
216
+
217
+ ## License
218
+
219
+ MIT License. See LICENSE file for details.
@@ -0,0 +1,198 @@
1
+ # NomadicML Python SDK
2
+
3
+ A Python client library for the NomadicML DriveMonitor API, allowing you to upload and analyze driving videos programmatically.
4
+
5
+ ## Installation
6
+
7
+ ### From PyPI (for users)
8
+
9
+ ```bash
10
+ pip install nomadicml
11
+ ```
12
+
13
+ ### For Development (from source)
14
+
15
+ To install the package in development mode, where changes to the code will be immediately reflected without reinstallation:
16
+
17
+ ```bash
18
+ # Clone the repository
19
+ git clone https://github.com/nomadic-ml/drivemonitor.git
20
+ cd sdk
21
+
22
+ # For development: Install in editable mode
23
+ pip install -e .
24
+ ```
25
+
26
+ With this installation, any changes you make to the code will be immediately available when you import the package.
27
+
28
+ ## Quick Start
29
+
30
+ ```python
31
+ from nomadicml import NomadicML
32
+
33
+ # Initialize the client with your API key
34
+ client = NomadicML(api_key="your_api_key")
35
+
36
+ # Upload a video and analyze it in one step
37
+ result = client.video.upload_and_analyze("path/to/your/video.mp4")
38
+
39
+ # Print the detected events
40
+ for event in result["events"]:
41
+ print(f"Event: {event['type']} at {event['time']}s - {event['description']}")
42
+ #For a batch upload
43
+
44
+ videos_list = [.....]#list of video paths
45
+ batch_results = client.video.upload_and_analyze_videos(videos_list, wait_for_completion=False)
46
+
47
+
48
+ video_ids = [
49
+ res.get("video_id")
50
+ for res in batch_results
51
+ if res # safety for None
52
+ ]
53
+
54
+
55
+ full_results = client.video.wait_for_analyses(video_ids)
56
+
57
+ ```
58
+
59
+ ## Authentication
60
+
61
+ You need an API key to use the NomadicML API. You can get one by:
62
+
63
+ 1. Log in to your DriveMonitor account
64
+ 2. Go to Profile > API Key
65
+ 3. Generate a new API key
66
+
67
+ Then use this key when initializing the client:
68
+
69
+ ```python
70
+ client = NomadicML(api_key="your_api_key")
71
+ ```
72
+
73
+ ## Video Upload and Analysis
74
+
75
+ ### Upload a video
76
+
77
+ ```python
78
+ # Upload a local video file
79
+ result = client.video.upload_video(
80
+ source="file",
81
+ file_path="path/to/video.mp4"
82
+ )
83
+
84
+ # Or upload from YouTube
85
+ result = client.video.upload_video(
86
+ source="youtube",
87
+ youtube_url="https://www.youtube.com/watch?v=VIDEO_ID"
88
+ )
89
+
90
+ # Get the video ID from the response
91
+ video_id = result["video_id"]
92
+ ```
93
+
94
+ ### Analyze a video
95
+
96
+ ```python
97
+ # Start analysis
98
+ client.video.analyze_video(video_id)
99
+
100
+ # Wait for analysis to complete
101
+ status = client.video.wait_for_analysis(video_id)
102
+
103
+ # Get analysis results
104
+ analysis = client.video.get_video_analysis(video_id)
105
+
106
+ # Get detected events
107
+ events = client.video.get_video_events(video_id)
108
+ ```
109
+
110
+ ### Upload and analyze in one step
111
+
112
+ ```python
113
+ # Upload and analyze a video, waiting for results
114
+ analysis = client.video.upload_and_analyze("path/to/video.mp4")
115
+
116
+ # Or just start the process without waiting
117
+ result = client.video.upload_and_analyze("path/to/video.mp4", wait_for_completion=False)
118
+ ```
119
+
120
+ ## Advanced Usage
121
+
122
+ ### Filter events by severity or type
123
+
124
+ ```python
125
+ # Get only high severity events
126
+ high_severity_events = client.video.get_video_events(
127
+ video_id=video_id,
128
+ severity="high"
129
+ )
130
+
131
+ # Get only traffic violation events
132
+ traffic_violations = client.video.get_video_events(
133
+ video_id=video_id,
134
+ event_type="Traffic Violation"
135
+ )
136
+ ```
137
+
138
+ ### Custom timeout and polling interval
139
+
140
+ ```python
141
+ # Wait for analysis with a custom timeout and polling interval
142
+ client.video.wait_for_analysis(
143
+ video_id=video_id,
144
+ timeout=1200, # 20 minutes
145
+ poll_interval=10 # Check every 10 seconds
146
+ )
147
+ ```
148
+
149
+ ### Custom API endpoint
150
+
151
+ If you're using a custom deployment of the DriveMonitor backend:
152
+
153
+ ```python
154
+ # Connect to a local or custom deployment
155
+ client = NomadicML(
156
+ api_key="your_api_key",
157
+ base_url="http://localhost:8099"
158
+ )
159
+ ```
160
+
161
+ ## Error Handling
162
+
163
+ The SDK provides specific exceptions for different error types:
164
+
165
+ ```python
166
+ from nomadicml import NomadicMLError, AuthenticationError, VideoUploadError
167
+
168
+ try:
169
+ client.video.upload_and_analyze("path/to/video.mp4")
170
+ except AuthenticationError:
171
+ print("API key is invalid or expired")
172
+ except VideoUploadError as e:
173
+ print(f"Failed to upload video: {e}")
174
+ except NomadicMLError as e:
175
+ print(f"An error occurred: {e}")
176
+ ```
177
+
178
+ ## Development
179
+
180
+ ### Setup
181
+
182
+ Clone the repository and install development dependencies:
183
+
184
+ ```bash
185
+ git clone https://github.com/nomadicml/nomadicml-python.git
186
+ cd nomadicml-python
187
+ pip install -e ".[dev]"
188
+ ```
189
+
190
+ ### Running tests
191
+
192
+ ```bash
193
+ pytest
194
+ ```
195
+
196
+ ## License
197
+
198
+ MIT License. See LICENSE file for details.
@@ -0,0 +1,226 @@
1
+ """
2
+ Basic usage examples for the NomadicML SDK.
3
+ """
4
+
5
+ import os
6
+ import logging
7
+ from nomadicml import NomadicML
8
+
9
+ # Set up logging to see progress information
10
+ logging.basicConfig(level=logging.INFO)
11
+
12
+ # Get API key from environment variable or input
13
+ API_KEY = os.environ.get("NOMADICML_API_KEY") or input("Enter your NomadicML API key: ")
14
+
15
+ # Path to a video file for testing
16
+ VIDEO_PATH = os.environ.get("VIDEO_PATH") or input("Enter path to a video file: ")
17
+
18
+ # Initialize the client with your API key
19
+ # Add base_url for development use
20
+ # Change collection_name to "videos" for production use
21
+ client = NomadicML(api_key=API_KEY, collection_name="videos_dev")
22
+
23
+ def verify_authentication():
24
+ """
25
+ Verify that the API key is valid.
26
+ """
27
+ print("\n=== Verifying Authentication ===")
28
+ try:
29
+ # Verify authentication
30
+ auth_info = client.verify_auth()
31
+ print(f"Authentication successful: {auth_info}")
32
+ return True
33
+ except Exception as e:
34
+ print(f"Authentication failed due to error: {e}")
35
+ return False
36
+
37
+ def upload_video():
38
+ """
39
+ Upload a video file to the DriveMonitor API.
40
+ """
41
+ print("\n=== Uploading Video ===")
42
+ try:
43
+ # Upload the video
44
+ result = client.video.upload_video(
45
+ source="file",
46
+ file_path=VIDEO_PATH
47
+ )
48
+ video_id = result["video_id"]
49
+ print(f"Video uploaded successfully. ID: {video_id}")
50
+ return video_id
51
+ except Exception as e:
52
+ print(f"Video upload failed: {e}")
53
+ return None
54
+
55
+ def analyze_video(video_id):
56
+ """
57
+ Start analysis for the uploaded video.
58
+ """
59
+ print("\n=== Starting Video Analysis ===")
60
+ try:
61
+ # Start analysis
62
+ result = client.video.analyze_video(video_id)
63
+ print(f"Analysis started: {result}")
64
+ return True
65
+ except Exception as e:
66
+ print(f"Failed to start analysis: {e}")
67
+ return False
68
+
69
+ def check_status(video_id):
70
+ """
71
+ Check the status of the video analysis.
72
+ """
73
+ print("\n=== Checking Video Status ===")
74
+ try:
75
+ # Get the status
76
+ status = client.video.get_video_status(video_id)
77
+ print(f"Current status: {status}")
78
+ return status
79
+ except Exception as e:
80
+ print(f"Failed to get status: {e}")
81
+ return None
82
+
83
+ def wait_for_completion(video_id):
84
+ """
85
+ Wait for the video analysis to complete.
86
+ """
87
+ print("\n=== Waiting for Analysis to Complete ===")
88
+ try:
89
+ # Wait for completion with a shorter timeout for the example
90
+ final_status = client.video.wait_for_analysis(video_id, timeout=180)
91
+ print(f"Analysis completed: {final_status.get('status', 'Unknown')}")
92
+ return True
93
+ except Exception as e:
94
+ print(f"Error waiting for completion: {e}")
95
+ return False
96
+
97
+ def get_results(video_id):
98
+ """
99
+ Get the full analysis results.
100
+ """
101
+ print("\n=== Getting Analysis Results ===")
102
+ try:
103
+ # Get the analysis
104
+ analysis = client.video.get_video_analysis(video_id)
105
+ print(f"Analysis summary:")
106
+
107
+ # Print metadata if available
108
+ if "metadata" in analysis:
109
+ metadata = analysis["metadata"]
110
+ print(f" Video: {metadata.get('filename', 'Unknown')}")
111
+ if "duration" in metadata:
112
+ print(f" Duration: {metadata['duration']:.2f} seconds")
113
+ if "width" in metadata and "height" in metadata:
114
+ print(f" Resolution: {metadata['width']}x{metadata['height']}")
115
+
116
+ # Print events if available
117
+ if "events" in analysis and analysis["events"]:
118
+ print(f"\nDetected events ({len(analysis['events'])}):")
119
+ else:
120
+ print("\nNo events detected.")
121
+
122
+ return analysis
123
+ except Exception as e:
124
+ print(f"Failed to get analysis results: {e}")
125
+ return None
126
+
127
+ def upload_and_analyze_in_one_step(return_subset: bool = True):
128
+ """
129
+ Upload and analyze a video in one operation.
130
+ """
131
+ print("\n=== Upload and Analyze in One Step ===")
132
+ try:
133
+ # Upload and analyze with a shorter timeout for the example
134
+ analysis = client.video.upload_and_analyze(
135
+ file_path=VIDEO_PATH,
136
+ timeout=180,
137
+ return_subset=return_subset
138
+ )
139
+ print(f"Upload and analysis completed successfully.")
140
+
141
+ # Print a summary of the results
142
+ if hasattr(analysis, 'visual_analysis') and analysis.visual_analysis and hasattr(analysis.visual_analysis, 'events') and analysis.visual_analysis.events:
143
+ print(f"\nDetected {len(analysis.visual_analysis.events)} events.")
144
+ elif isinstance(analysis, dict) and "events" in analysis and analysis["events"]: # Keep compatibility if return_subset=False
145
+ print(f"\nDetected {len(analysis['events'])} events.")
146
+ else:
147
+ print("\nNo events detected.")
148
+
149
+ return analysis
150
+ except Exception as e:
151
+ print(f"Upload and analyze failed: {e}")
152
+ return None
153
+
154
+ def main():
155
+ """
156
+ Run the examples.
157
+ """
158
+ print("=== NomadicML SDK Basic Usage Example ===")
159
+
160
+ # Verify authentication
161
+ if not verify_authentication():
162
+ print("Exiting due to authentication failure.")
163
+ return
164
+
165
+ # Ask which example to run
166
+ print("\nChoose an example to run:")
167
+ print("1. Step-by-step (upload, analyze, get results)")
168
+ print("2. All-in-one (upload and analyze in one step)")
169
+ print("3. Only upload video")
170
+ print("4. Only analyze video")
171
+
172
+ choice = input("Enter your choice (1, 2, 3 or 4): ").strip()
173
+
174
+ if choice == "1":
175
+ # Step-by-step example
176
+ video_id = upload_video()
177
+ if not video_id:
178
+ print("Exiting due to upload failure.")
179
+ return
180
+
181
+ if not analyze_video(video_id):
182
+ print("Exiting due to analysis startup failure.")
183
+ return
184
+
185
+ status = check_status(video_id)
186
+ if not status:
187
+ print("Exiting due to status check failure.")
188
+ return
189
+
190
+ if not wait_for_completion(video_id):
191
+ print("Exiting due to timeout or error while waiting for completion.")
192
+ return
193
+
194
+ results = get_results(video_id)
195
+ if not results:
196
+ print("Exiting due to failure getting results.")
197
+ return
198
+
199
+ elif choice == "2":
200
+ # All-in-one example
201
+ results = upload_and_analyze_in_one_step()
202
+ if not results:
203
+ print("Exiting due to upload and analyze failure.")
204
+ return
205
+ elif choice == "3":
206
+ # Only upload video
207
+ print("\n=== Only Uploading Video ===")
208
+ video_id = upload_video()
209
+ if not video_id:
210
+ print("Exiting due to upload failure.")
211
+ return
212
+ elif choice == "4":
213
+ # Only analyze video
214
+ print("\n=== Only Analyzing Video ===")
215
+ video_id = input("Enter the video ID to analyze: ")
216
+ if not analyze_video(video_id):
217
+ print("Exiting due to analysis startup failure.")
218
+ return
219
+ else:
220
+ print("Invalid choice. Exiting.")
221
+ return
222
+
223
+ print("\n=== Example Completed Successfully ===")
224
+
225
+ if __name__ == "__main__":
226
+ main()
@@ -0,0 +1,42 @@
1
+ """
2
+ NomadicML Python SDK for the DriveMonitor API.
3
+
4
+ This SDK provides a simple interface to interact with the
5
+ DriveMonitor backend for analyzing driving videos.
6
+ """
7
+
8
+ __version__ = "0.1.0"
9
+
10
+ from .client import NomadicML
11
+ from .video import VideoClient
12
+ from .exceptions import NomadicMLError, AuthenticationError, APIError, VideoUploadError, AnalysisError
13
+ from .types import VideoSource, ProcessingStatus, Severity, convert_to_upload_analyze_response_subset
14
+
15
+ # Add video client to NomadicML
16
+ def _add_video_client(client):
17
+ client.video = VideoClient(client)
18
+ return client
19
+
20
+ # Patch the NomadicML class
21
+ _original_init = NomadicML.__init__
22
+
23
+ def _patched_init(self, *args, **kwargs):
24
+ _original_init(self, *args, **kwargs)
25
+ _add_video_client(self)
26
+
27
+ NomadicML.__init__ = _patched_init
28
+
29
+ __all__ = [
30
+ "NomadicML",
31
+ "VideoClient",
32
+ "NomadicMLError",
33
+ "AuthenticationError",
34
+ "APIError",
35
+ "VideoUploadError",
36
+ "AnalysisError",
37
+ "VideoSource",
38
+ "ProcessingStatus",
39
+ "EventType",
40
+ "Severity",
41
+ "convert_to_upload_analyze_response_subset",
42
+ ]