deepxl-python-sdk 1.0.0__py3-none-any.whl → 1.2.1__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.
deepxl/__init__.py ADDED
@@ -0,0 +1,49 @@
1
+ """DeepXL Python SDK"""
2
+
3
+ from .client import DeepXLClient
4
+ from .types import (
5
+ Tag,
6
+ FileData,
7
+ ModelMetadata,
8
+ FraudDetection,
9
+ DetectionHistoryResponse,
10
+ DetectionResponse,
11
+ DetectionQueryParams,
12
+ AnalyzeFileOptions,
13
+ APIParse,
14
+ APIParseHistoryResponse,
15
+ APIParseResponse,
16
+ ParseQueryParams,
17
+ ParseDocumentOptions,
18
+ Verification,
19
+ VerificationResponse,
20
+ APIVerificationHistoryResponse,
21
+ VerificationQueryParams,
22
+ VerifyOptions,
23
+ DeepXLClientConfig,
24
+ )
25
+
26
+ __all__ = [
27
+ 'DeepXLClient',
28
+ 'Tag',
29
+ 'FileData',
30
+ 'ModelMetadata',
31
+ 'FraudDetection',
32
+ 'DetectionHistoryResponse',
33
+ 'DetectionResponse',
34
+ 'DetectionQueryParams',
35
+ 'AnalyzeFileOptions',
36
+ 'APIParse',
37
+ 'APIParseHistoryResponse',
38
+ 'APIParseResponse',
39
+ 'ParseQueryParams',
40
+ 'ParseDocumentOptions',
41
+ 'Verification',
42
+ 'VerificationResponse',
43
+ 'APIVerificationHistoryResponse',
44
+ 'VerificationQueryParams',
45
+ 'VerifyOptions',
46
+ 'DeepXLClientConfig',
47
+ ]
48
+
49
+ __version__ = '1.0.0'
deepxl/client.py ADDED
@@ -0,0 +1,278 @@
1
+ """DeepXL API Client"""
2
+
3
+ import json
4
+ import requests
5
+ from typing import Optional, Dict, Any, Union, List
6
+ from io import BytesIO
7
+
8
+ from .types import (
9
+ DeepXLClientConfig,
10
+ ModelMetadata,
11
+ DetectionHistoryResponse,
12
+ DetectionResponse,
13
+ DetectionQueryParams,
14
+ AnalyzeFileOptions,
15
+ APIParseHistoryResponse,
16
+ APIParseResponse,
17
+ ParseQueryParams,
18
+ ParseDocumentOptions,
19
+ APIVerificationHistoryResponse,
20
+ VerificationResponse,
21
+ VerificationQueryParams,
22
+ VerifyOptions,
23
+ )
24
+
25
+
26
+ class DeepXLClient:
27
+ """Client for interacting with the DeepXL API"""
28
+
29
+ BASE_URL = 'https://api.deepxl.ai'
30
+
31
+ def __init__(self, config: DeepXLClientConfig):
32
+ """
33
+ Initialize the DeepXL client.
34
+
35
+ Args:
36
+ config: Configuration object containing apiKey
37
+ """
38
+ if not config.apiKey:
39
+ raise ValueError('apiKey must be provided')
40
+ self.api_key = config.apiKey
41
+ self.base_url = self.BASE_URL
42
+
43
+ def _get_headers(self) -> Dict[str, str]:
44
+ """Get default headers for API requests"""
45
+ return {
46
+ 'x-api-key': self.api_key,
47
+ }
48
+
49
+ def _request(
50
+ self,
51
+ method: str,
52
+ path: str,
53
+ params: Optional[Dict[str, Any]] = None,
54
+ files: Optional[Dict[str, Any]] = None,
55
+ data: Optional[Dict[str, Any]] = None,
56
+ ) -> Any:
57
+ """
58
+ Make an HTTP request to the API.
59
+
60
+ Args:
61
+ method: HTTP method (GET, POST, etc.)
62
+ path: API endpoint path
63
+ params: Query parameters
64
+ files: Files to upload (for multipart/form-data)
65
+ data: Form data (for multipart/form-data)
66
+
67
+ Returns:
68
+ Response JSON data
69
+
70
+ Raises:
71
+ ValueError: If the request fails
72
+ """
73
+ url = f'{self.base_url}{path}'
74
+ headers = self._get_headers()
75
+
76
+ # Prepare query parameters
77
+ query_params = {}
78
+ if params:
79
+ for key, value in params.items():
80
+ if value is not None:
81
+ query_params[key] = value
82
+
83
+ try:
84
+ if files or data:
85
+ # Multipart form data request
86
+ response = requests.request(
87
+ method=method,
88
+ url=url,
89
+ headers=headers,
90
+ params=query_params,
91
+ files=files,
92
+ data=data,
93
+ )
94
+ else:
95
+ # JSON request
96
+ response = requests.request(
97
+ method=method,
98
+ url=url,
99
+ headers=headers,
100
+ params=query_params,
101
+ )
102
+
103
+ response.raise_for_status()
104
+
105
+ # Handle file downloads
106
+ content_type = response.headers.get('content-type', '')
107
+ if 'application/octet-stream' in content_type:
108
+ return response
109
+
110
+ return response.json()
111
+
112
+ except requests.exceptions.HTTPError as e:
113
+ error_message = str(e)
114
+ try:
115
+ error_json = response.json()
116
+ error_message = error_json.get('detail') or error_json.get('message') or error_message
117
+ except:
118
+ pass
119
+ raise ValueError(error_message) from e
120
+
121
+ def _prepare_file(self, file: Union[bytes, Any], filename: Optional[str] = None) -> tuple:
122
+ """
123
+ Prepare a file for upload.
124
+
125
+ Args:
126
+ file: File data (bytes or file-like object)
127
+ filename: Optional filename
128
+
129
+ Returns:
130
+ Tuple of (file_data, filename)
131
+ """
132
+ if isinstance(file, bytes):
133
+ file_obj = BytesIO(file)
134
+ filename = filename or 'file'
135
+ else:
136
+ # Assume it's a file-like object
137
+ file_obj = file
138
+ if hasattr(file, 'name'):
139
+ filename = filename or file.name
140
+ else:
141
+ filename = filename or 'file'
142
+
143
+ return (filename, file_obj)
144
+
145
+ # Fraud Detection Methods
146
+ def get_detection_models(self) -> List[ModelMetadata]:
147
+ """Get available fraud detection models"""
148
+ return self._request('GET', '/v1/detection-models')
149
+
150
+ def get_detection_history(self, params: Optional[DetectionQueryParams] = None) -> DetectionHistoryResponse:
151
+ """Get fraud detection history"""
152
+ return self._request('GET', '/v1/detection', params=params)
153
+
154
+ def get_detection_by_id(self, detection_id: int) -> DetectionResponse:
155
+ """Get a fraud detection record by ID"""
156
+ return self._request('GET', f'/v1/detection/{detection_id}')
157
+
158
+ def analyze_file(self, options: AnalyzeFileOptions) -> DetectionResponse:
159
+ """
160
+ Analyze a file for fraud detection.
161
+
162
+ Args:
163
+ options: Options containing model, file, fileName, and optional tags
164
+
165
+ Returns:
166
+ Detection response with analysis results
167
+ """
168
+ filename, file_obj = self._prepare_file(options.file, options.fileName)
169
+
170
+ files = {
171
+ 'file': (filename, file_obj),
172
+ }
173
+
174
+ data = {
175
+ 'model': options.model,
176
+ }
177
+
178
+ if options.tags:
179
+ data['tags'] = json.dumps(options.tags)
180
+
181
+ return self._request('POST', '/v1/detection', files=files, data=data)
182
+
183
+ # Document Parsing Methods
184
+ def get_parsing_models(self) -> List[ModelMetadata]:
185
+ """Get available parsing models"""
186
+ return self._request('GET', '/v1/parsing-models')
187
+
188
+ def get_parsing_history(self, params: Optional[ParseQueryParams] = None) -> APIParseHistoryResponse:
189
+ """Get document parsing history"""
190
+ return self._request('GET', '/v1/parse', params=params)
191
+
192
+ def get_parse_by_id(self, parse_id: int) -> APIParseResponse:
193
+ """Get a parsed document by ID"""
194
+ return self._request('GET', f'/v1/parse/{parse_id}')
195
+
196
+ def parse_document(self, options: ParseDocumentOptions) -> APIParseResponse:
197
+ """
198
+ Parse a document.
199
+
200
+ Args:
201
+ options: Options containing model, file, fileName, and optional tags
202
+
203
+ Returns:
204
+ Parse response with extracted data
205
+ """
206
+ filename, file_obj = self._prepare_file(options.file, options.fileName)
207
+
208
+ files = {
209
+ 'file': (filename, file_obj),
210
+ }
211
+
212
+ data = {
213
+ 'model': options.model,
214
+ }
215
+
216
+ if options.tags:
217
+ data['tags'] = json.dumps(options.tags)
218
+
219
+ return self._request('POST', '/v1/parse', files=files, data=data)
220
+
221
+ # Verification Methods
222
+ def get_verification_history(self, params: Optional[VerificationQueryParams] = None) -> APIVerificationHistoryResponse:
223
+ """Get verification history"""
224
+ return self._request('GET', '/v1/verification', params=params)
225
+
226
+ def get_verification_by_id(self, verification_id: int) -> VerificationResponse:
227
+ """Get a verification record by ID"""
228
+ return self._request('GET', f'/v1/verification/{verification_id}')
229
+
230
+ def verify(self, options: VerifyOptions) -> VerificationResponse:
231
+ """
232
+ Verify a user with their ID and selfie.
233
+
234
+ Args:
235
+ options: Options containing idFile, selfieFile, and optional tags
236
+
237
+ Returns:
238
+ Verification response with verification results
239
+ """
240
+ id_filename, id_file_obj = self._prepare_file(options.idFile, options.idFileName)
241
+ selfie_filename, selfie_file_obj = self._prepare_file(options.selfieFile, options.selfieFileName)
242
+
243
+ files = {
244
+ 'idFile': (id_filename, id_file_obj),
245
+ 'selfieFile': (selfie_filename, selfie_file_obj),
246
+ }
247
+
248
+ data = {}
249
+ if options.tags:
250
+ data['tags'] = json.dumps(options.tags)
251
+
252
+ return self._request('POST', '/v1/verification', files=files, data=data)
253
+
254
+ # File Retrieval Methods
255
+ def get_file(self, file_name: str) -> requests.Response:
256
+ """
257
+ Get a file from the API.
258
+
259
+ Args:
260
+ file_name: Name of the file to retrieve
261
+
262
+ Returns:
263
+ Response object with file content
264
+ """
265
+ return self._request('GET', f'/v1/files/{file_name}')
266
+
267
+ def download_file(self, file_name: str) -> bytes:
268
+ """
269
+ Download a file from the API.
270
+
271
+ Args:
272
+ file_name: Name of the file to download
273
+
274
+ Returns:
275
+ File content as bytes
276
+ """
277
+ response = self.get_file(file_name)
278
+ return response.content
deepxl/types.py ADDED
@@ -0,0 +1,205 @@
1
+ """Type definitions for DeepXL API"""
2
+
3
+ from typing import TypedDict, Optional, List, Dict, Any, Union, Literal
4
+ from dataclasses import dataclass
5
+
6
+
7
+ class Tag(TypedDict):
8
+ name: str
9
+ value: str
10
+
11
+
12
+ class FileData(TypedDict, total=False):
13
+ category: Optional[str]
14
+ fileName: str
15
+ fileSize: int
16
+ contentType: str
17
+ timestamp: int
18
+ timestampISO: str
19
+ url: Optional[str]
20
+
21
+
22
+ class ModelMetadata(TypedDict):
23
+ name: str
24
+ description: str
25
+ tags: List[str]
26
+ category: str
27
+ validInputTypes: List[str]
28
+ validFileTypes: List[str]
29
+ ownedBy: str
30
+ version: str
31
+
32
+
33
+ # Fraud Detection Types
34
+ class FraudDetection(TypedDict, total=False):
35
+ detectionId: int
36
+ mediaType: str
37
+ fileName: str
38
+ size: int
39
+ fileType: str
40
+ model: str
41
+ likelihood: float
42
+ fraudSeverity: Literal["low", "medium", "high"]
43
+ reasoning: List[str]
44
+ modelResults: Dict[str, Any]
45
+ classification: Optional[str]
46
+ timestamp: int
47
+ timestampISO: str
48
+ tags: List[Tag]
49
+ files: List[FileData]
50
+
51
+
52
+ class DetectionHistoryResponse(TypedDict):
53
+ totalCount: int
54
+ count: int
55
+ data: List[FraudDetection]
56
+
57
+
58
+ class DetectionResponse(TypedDict):
59
+ result: FraudDetection
60
+
61
+
62
+ class DetectionQueryParams(TypedDict, total=False):
63
+ limit: Optional[int]
64
+ offset: Optional[int]
65
+ sortBy: Optional[Literal["fraudDetectionId", "fileName", "size", "fileType", "model", "likelihood", "createdOn"]]
66
+ direction: Optional[Literal["asc", "desc"]]
67
+ tagFilter: Optional[str]
68
+ mediaType: Optional[str]
69
+ fileType: Optional[str]
70
+ fileName: Optional[str]
71
+ model: Optional[str]
72
+ minLikelihood: Optional[float]
73
+ maxLikelihood: Optional[float]
74
+ fraudSeverity: Optional[Literal["low", "medium", "high"]]
75
+ classification: Optional[str]
76
+ minTimestamp: Optional[int]
77
+ maxTimestamp: Optional[int]
78
+
79
+
80
+ @dataclass
81
+ class AnalyzeFileOptions:
82
+ model: str
83
+ file: Union[bytes, Any] # bytes or file-like object
84
+ fileName: Optional[str] = None
85
+ tags: Optional[Dict[str, str]] = None
86
+
87
+
88
+ # Document Parsing Types
89
+ class APIParse(TypedDict, total=False):
90
+ parseId: int
91
+ mediaType: str
92
+ fileType: str
93
+ fileName: str
94
+ size: int
95
+ model: str
96
+ likelihood: float
97
+ documentType: str
98
+ parsedData: Dict[str, Any]
99
+ timestamp: int
100
+ timestampISO: str
101
+ tags: List[Tag]
102
+ files: List[FileData]
103
+
104
+
105
+ class APIParseHistoryResponse(TypedDict):
106
+ totalCount: int
107
+ count: int
108
+ data: List[APIParse]
109
+
110
+
111
+ class APIParseResponse(TypedDict):
112
+ result: APIParse
113
+
114
+
115
+ class ParseQueryParams(TypedDict, total=False):
116
+ limit: Optional[int]
117
+ offset: Optional[int]
118
+ sortBy: Optional[Literal["parseId", "mediaType", "fileType", "fileName", "size", "confidence", "documentType", "timestamp"]]
119
+ direction: Optional[Literal["asc", "desc"]]
120
+ tagFilter: Optional[str]
121
+ mediaType: Optional[str]
122
+ fileType: Optional[str]
123
+ fileName: Optional[str]
124
+ minSize: Optional[int]
125
+ maxSize: Optional[int]
126
+ model: Optional[str]
127
+ documentType: Optional[str]
128
+ minTimestamp: Optional[int]
129
+ maxTimestamp: Optional[int]
130
+
131
+
132
+ @dataclass
133
+ class ParseDocumentOptions:
134
+ model: str
135
+ file: Union[bytes, Any] # bytes or file-like object
136
+ fileName: Optional[str] = None
137
+ tags: Optional[Dict[str, str]] = None
138
+
139
+
140
+ # Verification Types
141
+ class TechnicalCheck(TypedDict, total=False):
142
+ type: str
143
+ status: str
144
+ confidence: Optional[float]
145
+ details: Optional[str]
146
+
147
+
148
+ class Verification(TypedDict, total=False):
149
+ verificationId: int
150
+ idName: str
151
+ idSize: int
152
+ idFileType: str
153
+ selfieName: str
154
+ selfieSize: int
155
+ selfieFileType: str
156
+ verified: bool
157
+ technicalChecks: List[TechnicalCheck]
158
+ timestamp: int
159
+ timestampISO: str
160
+ tags: List[Tag]
161
+ files: List[FileData]
162
+
163
+
164
+ class VerificationResponse(TypedDict):
165
+ result: Verification
166
+
167
+
168
+ class APIVerificationHistoryResponse(TypedDict):
169
+ totalCount: int
170
+ count: int
171
+ data: List[Verification]
172
+
173
+
174
+ class VerificationQueryParams(TypedDict, total=False):
175
+ limit: Optional[int]
176
+ offset: Optional[int]
177
+ sortBy: Optional[Literal["verificationId", "idName", "idSize", "idFileType", "selfieName", "selfieSize", "selfieFileType", "verified", "timestamp"]]
178
+ direction: Optional[Literal["asc", "desc"]]
179
+ tagFilter: Optional[str]
180
+ idName: Optional[str]
181
+ idFileType: Optional[str]
182
+ selfieName: Optional[str]
183
+ selfieFileType: Optional[str]
184
+ minIdSize: Optional[int]
185
+ maxIdSize: Optional[int]
186
+ minSelfieSize: Optional[int]
187
+ maxSelfieSize: Optional[int]
188
+ verified: Optional[bool]
189
+ minTimestamp: Optional[int]
190
+ maxTimestamp: Optional[int]
191
+
192
+
193
+ @dataclass
194
+ class VerifyOptions:
195
+ idFile: Union[bytes, Any] # bytes or file-like object
196
+ idFileName: Optional[str] = None
197
+ selfieFile: Union[bytes, Any] # bytes or file-like object
198
+ selfieFileName: Optional[str] = None
199
+ tags: Optional[Dict[str, str]] = None
200
+
201
+
202
+ # Client Configuration
203
+ @dataclass
204
+ class DeepXLClientConfig:
205
+ apiKey: str
@@ -0,0 +1,326 @@
1
+ Metadata-Version: 2.4
2
+ Name: deepxl-python-sdk
3
+ Version: 1.2.1
4
+ Summary: Python SDK for DeepXL fraud detection, document parsing, and verification services
5
+ Home-page: https://github.com/deepxl/deepxl-python-sdk
6
+ Author: DeepXL
7
+ Author-email: david@deepxl.ai
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Requires-Python: >=3.8
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: requests>=2.28.0
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: home-page
27
+ Dynamic: requires-dist
28
+ Dynamic: requires-python
29
+ Dynamic: summary
30
+
31
+ # DeepXL Python SDK
32
+
33
+ Python SDK for DeepXL fraud detection, document parsing, verification, and file retrieval services.
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install deepxl
39
+ ```
40
+
41
+ Or install from source:
42
+
43
+ ```bash
44
+ pip install -r requirements.txt
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ### Initialize the Client
50
+
51
+ ```python
52
+ from deepxl import DeepXLClient, DeepXLClientConfig
53
+
54
+ config = DeepXLClientConfig(apiKey='your-api-key-here')
55
+ client = DeepXLClient(config)
56
+ ```
57
+
58
+ ## Fraud Detection
59
+
60
+ ### Get Available Models
61
+
62
+ ```python
63
+ models = client.get_detection_models()
64
+ print(models)
65
+ ```
66
+
67
+ ### Analyze a File for Fraud Detection
68
+
69
+ ```python
70
+ from deepxl import AnalyzeFileOptions
71
+
72
+ # Read file as bytes
73
+ with open('document.jpg', 'rb') as f:
74
+ file_data = f.read()
75
+
76
+ options = AnalyzeFileOptions(
77
+ model='document', # or 'object'
78
+ file=file_data,
79
+ fileName='document.jpg',
80
+ tags={
81
+ 'customerId': '9999',
82
+ 'customerName': 'Acme Corp',
83
+ 'documentId': 'DOC-2024-001'
84
+ }
85
+ )
86
+
87
+ result = client.analyze_file(options)
88
+ print(result['result'])
89
+ ```
90
+
91
+ ### Get Detection History
92
+
93
+ ```python
94
+ from deepxl import DetectionQueryParams
95
+
96
+ params = DetectionQueryParams(
97
+ limit=25,
98
+ offset=0,
99
+ sortBy='createdOn',
100
+ direction='desc',
101
+ fraudSeverity='high',
102
+ minLikelihood=70
103
+ )
104
+
105
+ history = client.get_detection_history(params)
106
+ print(history['data'])
107
+ ```
108
+
109
+ ### Get Detection by ID
110
+
111
+ ```python
112
+ detection = client.get_detection_by_id(123)
113
+ print(detection['result'])
114
+ ```
115
+
116
+ ## Document Parsing
117
+
118
+ ### Get Available Parsing Models
119
+
120
+ ```python
121
+ models = client.get_parsing_models()
122
+ print(models)
123
+ ```
124
+
125
+ ### Parse a Document
126
+
127
+ ```python
128
+ from deepxl import ParseDocumentOptions
129
+
130
+ # Read file as bytes
131
+ with open('drivers_license.jpg', 'rb') as f:
132
+ file_data = f.read()
133
+
134
+ options = ParseDocumentOptions(
135
+ model='light', # or 'performance'
136
+ file=file_data,
137
+ fileName='drivers_license.jpg',
138
+ tags={
139
+ 'customerId': '9999',
140
+ 'customerName': 'Acme Corp'
141
+ }
142
+ )
143
+
144
+ result = client.parse_document(options)
145
+ print(result['result']['parsedData'])
146
+ ```
147
+
148
+ ### Get Parse History
149
+
150
+ ```python
151
+ from deepxl import ParseQueryParams
152
+
153
+ params = ParseQueryParams(
154
+ limit=25,
155
+ offset=0,
156
+ sortBy='parseId',
157
+ direction='desc',
158
+ documentType='usa_driver_license'
159
+ )
160
+
161
+ history = client.get_parsing_history(params)
162
+ print(history['data'])
163
+ ```
164
+
165
+ ### Get Parse by ID
166
+
167
+ ```python
168
+ parse_result = client.get_parse_by_id(117)
169
+ print(parse_result['result'])
170
+ ```
171
+
172
+ ## Verification
173
+
174
+ ### Verify User with ID and Selfie
175
+
176
+ ```python
177
+ from deepxl import VerifyOptions
178
+
179
+ # Read files as bytes
180
+ with open('id.jpg', 'rb') as f:
181
+ id_data = f.read()
182
+
183
+ with open('selfie.jpg', 'rb') as f:
184
+ selfie_data = f.read()
185
+
186
+ options = VerifyOptions(
187
+ idFile=id_data,
188
+ idFileName='id.jpg',
189
+ selfieFile=selfie_data,
190
+ selfieFileName='selfie.jpg',
191
+ tags={
192
+ 'customerId': '9999',
193
+ 'customerName': 'Acme Corp'
194
+ }
195
+ )
196
+
197
+ result = client.verify(options)
198
+ print(result['result']['verified'])
199
+ print(result['result']['technicalChecks'])
200
+ ```
201
+
202
+ ### Get Verification History
203
+
204
+ ```python
205
+ from deepxl import VerificationQueryParams
206
+
207
+ params = VerificationQueryParams(
208
+ limit=25,
209
+ offset=0,
210
+ verified=True,
211
+ sortBy='timestamp',
212
+ direction='desc'
213
+ )
214
+
215
+ history = client.get_verification_history(params)
216
+ print(history['data'])
217
+ ```
218
+
219
+ ### Get Verification by ID
220
+
221
+ ```python
222
+ verification = client.get_verification_by_id(456)
223
+ print(verification['result'])
224
+ ```
225
+
226
+ ## File Retrieval
227
+
228
+ ### Download a File
229
+
230
+ ```python
231
+ file_bytes = client.download_file('fd_123_document.jpg')
232
+ with open('downloaded_file.jpg', 'wb') as f:
233
+ f.write(file_bytes)
234
+ ```
235
+
236
+ ### Get File as Response
237
+
238
+ ```python
239
+ response = client.get_file('fd_123_document.jpg')
240
+ file_bytes = response.content
241
+ with open('downloaded_file.jpg', 'wb') as f:
242
+ f.write(file_bytes)
243
+ ```
244
+
245
+ ## Type Definitions
246
+
247
+ All type definitions are available for import:
248
+
249
+ ```python
250
+ from deepxl import (
251
+ Tag,
252
+ FileData,
253
+ ModelMetadata,
254
+ FraudDetection,
255
+ DetectionResponse,
256
+ DetectionQueryParams,
257
+ AnalyzeFileOptions,
258
+ APIParse,
259
+ APIParseResponse,
260
+ ParseQueryParams,
261
+ ParseDocumentOptions,
262
+ Verification,
263
+ VerificationResponse,
264
+ VerificationQueryParams,
265
+ VerifyOptions,
266
+ )
267
+ ```
268
+
269
+ ## Error Handling
270
+
271
+ The SDK raises `ValueError` with descriptive error messages:
272
+
273
+ ```python
274
+ try:
275
+ result = client.analyze_file(options)
276
+ except ValueError as e:
277
+ print(f'Error: {e}')
278
+ # Error messages match API error responses
279
+ ```
280
+
281
+ ## Query Parameters
282
+
283
+ All query parameters are optional and can be used to filter and paginate results:
284
+
285
+ - `limit`: Number of results (1-100, default: 25)
286
+ - `offset`: Number of results to skip (default: 0)
287
+ - `sortBy`: Field to sort by
288
+ - `direction`: 'asc' or 'desc' (default: 'desc')
289
+ - `tagFilter`: Filter by tags in format 'tagName=tagValue'
290
+ - Various model-specific filters (see type definitions for details)
291
+
292
+ ## Tags
293
+
294
+ Tags are optional metadata that can be attached to analyses for organization and filtering:
295
+
296
+ ```python
297
+ tags = {
298
+ 'customerId': '9999',
299
+ 'customerName': 'Acme Corp',
300
+ 'documentId': 'DOC-2024-001',
301
+ 'companyName': 'DeepXL',
302
+ 'companyId': 'COMP-001'
303
+ }
304
+ ```
305
+
306
+ You can filter results by tags using the `tagFilter` query parameter:
307
+
308
+ ```python
309
+ params = DetectionQueryParams(tagFilter='customerId=9999')
310
+ history = client.get_detection_history(params)
311
+ ```
312
+
313
+ ## Using File Objects
314
+
315
+ You can also pass file-like objects directly:
316
+
317
+ ```python
318
+ # Using open file handle
319
+ with open('document.jpg', 'rb') as f:
320
+ options = AnalyzeFileOptions(
321
+ model='document',
322
+ file=f,
323
+ fileName='document.jpg'
324
+ )
325
+ result = client.analyze_file(options)
326
+ ```
@@ -0,0 +1,7 @@
1
+ deepxl/__init__.py,sha256=L0UbVAmAbJXkrlcA5-jvbiiB1i0Fy54Gpld1U3sau_U,1086
2
+ deepxl/client.py,sha256=8qh4Xk4nS71ySLaIFysei-0ErZ_pv7q6wbHDpDWilyY,8797
3
+ deepxl/types.py,sha256=WAW00trHX8vHREVXG0WshF1DiHF5llrrq_w7xhYqXhs,5181
4
+ deepxl_python_sdk-1.2.1.dist-info/METADATA,sha256=9s4BpDfeu-40hr5h5V0S13N65Hkdkm56gk4PGXf-NdQ,6976
5
+ deepxl_python_sdk-1.2.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
6
+ deepxl_python_sdk-1.2.1.dist-info/top_level.txt,sha256=b2ahz1A886yOBMBtbesRqvMnd9G8qLcKEvblJYAR9LM,7
7
+ deepxl_python_sdk-1.2.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1 @@
1
+ deepxl
@@ -1,9 +0,0 @@
1
- from .client import DeepXLClient, UsageResponse, AnalysisResponse
2
- from .error import DeepXLError
3
-
4
- __all__ = [
5
- "DeepXLClient",
6
- "UsageResponse",
7
- "AnalysisResponse",
8
- "DeepXLError"
9
- ]
@@ -1,158 +0,0 @@
1
- import requests
2
- from .mimetypes import get_mimetype
3
- from .error import DeepXLError
4
- import re
5
-
6
- URL = "https://api.deepxl.ai/"
7
-
8
-
9
- class UsageResponse:
10
- def __init__(self, image_usage_limit, image_usage, video_usage_limit, video_usage, audio_usage_limit, audio_usage, document_usage_limit, document_usage):
11
- self.image_usage_limit = image_usage_limit
12
- self.image_usage = image_usage
13
- self.video_usage_limit = video_usage_limit
14
- self.video_usage = video_usage
15
- self.audio_usage_limit = audio_usage_limit
16
- self.audio_usage = audio_usage
17
- self.document_usage_limit = document_usage_limit
18
- self.document_usage = document_usage
19
-
20
-
21
- def __str__(self):
22
- return f"Image Usage: {self.image_usage} / {self.image_usage_limit}\nVideo Usage: {self.video_usage} / {self.video_usage_limit}\nAudio Usage: {self.audio_usage} / {self.audio_usage_limit}\nDocument Usage: {self.document_usage} / {self.document_usage_limit}"
23
-
24
-
25
- class AnalysisResponse:
26
- def __init__(self, likelihood, reasoning, model_results: dict):
27
- self.likelihood = likelihood
28
- self.reasoning = reasoning
29
- self.model_results = model_results
30
-
31
-
32
- def __str__(self):
33
- return f"Likelihood: {self.likelihood}\nReasoning: {self.reasoning}\nModel Results: {self.model_results}"
34
-
35
-
36
- def handle_http_error(res):
37
- json = res.json()
38
- # print(res.status_code, json)
39
- if res.status_code == 200:
40
- return
41
- if res.status_code == 400:
42
- raise DeepXLError(json["message"] if json["message"] else "Bad request.")
43
- if res.status_code == 401:
44
- raise DeepXLError("Invalid API key.")
45
- if res.status_code == 402:
46
- raise DeepXLError(json["message"] if json["message"] else "Usage limit reached.")
47
- if res.status_code == 403:
48
- pass
49
- if res.status_code == 404:
50
- raise DeepXLError(json["message"] if json["message"] else "Invalid model.")
51
- if res.status_code == 415:
52
- raise DeepXLError(json["message"] if json["message"] else "Invalid file type or file type is not compatible with the model.")
53
- if res.statusCode == 500:
54
- raise DeepXLError("Server error occured. Contact support or try again later.")
55
- raise DeepXLError(f"An unknown error occured. Status code: {res.status_code}, Response: {json}")
56
-
57
-
58
- class DeepXLClient:
59
- def __init__(self, api_key):
60
- self.api_key = api_key
61
-
62
-
63
- def check_usage(self):
64
- res = requests.get(
65
- URL + "v1/account/",
66
- headers={ "x-api-key": self.api_key },
67
- timeout=5.0
68
- )
69
- try:
70
- if res.status_code == 200:
71
- json = res.json()
72
- return UsageResponse(
73
- json["imageUsageLimit"],
74
- json["imageUsage"],
75
- json["videoUsageLimit"],
76
- json["videoUsage"],
77
- json["audioUsageLimit"],
78
- json["audioUsage"],
79
- json["documentUsageLimit"],
80
- json["documentUsage"]
81
- )
82
- else:
83
- handle_http_error(res)
84
- except ConnectionError as e:
85
- raise e
86
-
87
-
88
- def analyze(self, model_name: str, file_name: str, file_data: bytes):
89
- if (len(file_data) == 0):
90
- raise DeepXLError("File data is missing or invalid.")
91
- try:
92
- file_type = get_mimetype(file_name)
93
- res = requests.post(
94
- URL + "v1/analysis",
95
- headers={
96
- "x-api-key": self.api_key,
97
- },
98
- data={
99
- "model": model_name
100
- },
101
- files={
102
- "file": (file_name, file_data, file_type)
103
- },
104
- timeout=5.0
105
- )
106
- if res.status_code == 200:
107
- result = res.json()["result"]
108
- return AnalysisResponse(
109
- likelihood=result["likelihood"],
110
- reasoning=result["reasoning"],
111
- model_results=result["modelResults"]
112
- )
113
- else:
114
- handle_http_error(res)
115
- except ConnectionError as e:
116
- raise e
117
- except DeepXLError as e:
118
- raise e
119
-
120
-
121
- def analyze_file(self, model_name: str, file: str):
122
- f = None
123
- try:
124
- f = open(file, "rb")
125
- base_name = file.split(r"[\\/]+")[-1]
126
- file_type = get_mimetype(file)
127
- res = requests.post(
128
- URL + "v1/analysis",
129
- headers={
130
- "x-api-key": self.api_key,
131
- },
132
- data={
133
- "model": model_name
134
- },
135
- files={
136
- "file": (base_name, f, file_type)
137
- },
138
- timeout=5.0
139
- )
140
- f.close()
141
- if res.status_code == 200:
142
- result = res.json()["result"]
143
- return AnalysisResponse(
144
- likelihood=result["likelihood"],
145
- reasoning=result["reasoning"],
146
- model_results=result["modelResults"]
147
- )
148
- else:
149
- handle_http_error(res)
150
- except ConnectionError as e:
151
- if not f.closed:
152
- f.close()
153
- raise e
154
- except FileNotFoundError as e:
155
- raise DeepXLError(f'File "{file}" does not exist.')
156
- except DeepXLError as e:
157
- raise e
158
-
@@ -1,5 +0,0 @@
1
- class DeepXLError(Exception):
2
-
3
- def __init__(self, message: str):
4
- self.message = message
5
- super().__init__(self.message)
@@ -1,36 +0,0 @@
1
-
2
- # https://mimetype.io/all-types
3
-
4
- # This list is likely incomplete. Expand with need for more file compatibility
5
-
6
- def get_mimetype(filename: str):
7
- ext = filename.split('.')[-1]
8
- if (ext == 'jpg' or ext == 'jpeg'):
9
- return 'image/jpeg'
10
- elif ext == 'png':
11
- return 'image/png'
12
- elif ext == 'gif':
13
- return 'image/gif'
14
- elif ext == 'tif' or ext == 'tiff':
15
- return 'image/tiff'
16
- elif ext == 'bmp':
17
- return 'image/bmp'
18
- elif ext == 'mp4' or ext == 'mp4v' or ext == 'mpg4':
19
- return 'video/mp4'
20
- elif ext == 'avi':
21
- return 'video/x-msvideo'
22
- elif ext == 'wmv':
23
- return 'video/x-ms-wmv'
24
- elif ext == 'mpeg' or ext == 'mpg' or ext == 'mpe' or ext == 'm1v' or ext == 'm2v' or ext == 'mpa':
25
- return 'video/mpeg'
26
- elif ext == 'wav':
27
- return 'audio/wav'
28
- elif ext == 'mp3' or ext == 'mpga' or ext == 'm2a' or ext == 'm3a' or ext == 'mp2':
29
- return 'audio/mpeg'
30
- elif ext == 'wma':
31
- return 'audio/x-ma-wma'
32
- elif ext == 'wax':
33
- return 'audio/x-ms-wax'
34
- elif ext == 'pdf':
35
- return 'application/pdf'
36
- return None
@@ -1,92 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: deepxl-python-sdk
3
- Version: 1.0.0
4
- Summary: Python Software Development Kit for DeepXL AI Fraud Detection Services
5
- Author-email: deepxl <david@deepxl.ai>
6
- License-Expression: MIT
7
- Project-URL: Homepage, https://deepxl.ai
8
- Project-URL: Issues, https://github.com/deepxl/python-sdk
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.9
12
- Description-Content-Type: text/markdown
13
- License-File: LICENSE
14
- Dynamic: license-file
15
-
16
- # deepxl-python-sdk
17
- Python Software Development Kit for DeepXL fraud detection services
18
-
19
- ## Installation
20
-
21
- Install the SDK using pip
22
-
23
- ```bash
24
- pip install deepxl-python-sdk
25
- ```
26
-
27
- ## Example
28
-
29
- To use the DeepXL client, you must first create an API key in the [dashboard](https://app.deepxl.ai/settings?tab=apiKeys). You can create a new API key in Settings -> API Keys -> Create API Key.
30
-
31
- Treat this API key like you would any environment secret. Do not commit to a public repository or store in plain text.
32
-
33
- ```python
34
- from deepxl-python-sdk import DeepXLClient
35
-
36
- client = new DeepXLClient(MY_API_KEY)
37
-
38
- analysis_result = client.analyze_file("documents-model", ".\\file.pdf")
39
- ```
40
-
41
- ## Client methods
42
-
43
- ### check_usage
44
- Returns the monthly usage quota and current usage for the payment period for each media type.
45
-
46
- #### Returns:
47
-
48
- Returns a ```UsageResponse``` object with the following properties:
49
-
50
- |Property|Type|
51
- |----|----|
52
- |image_usage_limit|int|
53
- |image_usage|int|
54
- |video_usage_limit|int|
55
- |video_usage|int|
56
- |audio_usage_limit|int|
57
- |audio_usage|int|
58
- |document_usage_limit|int|
59
- |document_usage|int|
60
-
61
- ### analyze
62
-
63
- Analyze file data with DeepXL fraud detection.
64
-
65
- #### Inputs
66
-
67
- - **model_name:** the name of the model to use. You can find a complete list in our docs.
68
- - **file_name:** the name of the file to analyze
69
- - **file_data**: byte array of file data to analyze
70
-
71
- > Note: while you can use a constant string as file name, it is recommended you use unique identifiers to make files easier to find in analysis history.
72
-
73
- ### analyze_file
74
-
75
- Analyze file with DeepXL fraud detection. This does the same thing as ```analyze``` but takes a file path as input instead of binary file data.
76
-
77
- #### Inputs
78
-
79
- - **model_name:** the name of the model to use. You can find a complete list in our docs.
80
- - **file:** path of the file to analyze
81
-
82
- #### Returns
83
-
84
- Both ```analyze``` and ```analyze_file``` return an ```AnalysisResult``` object with the following properties:
85
-
86
- | Property | Type | Description |
87
- |----------|------|-|
88
- |likelihood|float|The percent likelihood that the file has been manipulated|
89
- |reasoning|str[]|model reasoning|
90
- |model_results|dict|model-specific outputs|
91
-
92
-
@@ -1,9 +0,0 @@
1
- deepxl_python_sdk/__init__.py,sha256=f9ore2vYiITQNfhY8wm-CG0UebQ6QIpMvpHJbqHi9SM,196
2
- deepxl_python_sdk/client.py,sha256=jcNIPtmFZavMtfXTKPnPWBgPeAHucf9gzfgeNG7cw84,4924
3
- deepxl_python_sdk/error.py,sha256=xsu0xp4yR48L0eTJtVi7bmIiG7psXg52TZ78_zfGodQ,132
4
- deepxl_python_sdk/mimetypes.py,sha256=EfXGU0Z6NKRYl_YV31_fJnM8RoxGWRCAltOH4EHrTPc,1090
5
- deepxl_python_sdk-1.0.0.dist-info/licenses/LICENSE,sha256=im3EHYsOJNyBv1TGpEPlVoa1gPzRiydDr3tRDUVDP_s,1087
6
- deepxl_python_sdk-1.0.0.dist-info/METADATA,sha256=b58WUuax8IMmuhEMOugNiuVxCurSyh0ZAzc-AS6zqFU,2756
7
- deepxl_python_sdk-1.0.0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
8
- deepxl_python_sdk-1.0.0.dist-info/top_level.txt,sha256=X1AYAPOdVnNRxDCBdmESz-kPg1hIPAenR9WM2nBWzMQ,18
9
- deepxl_python_sdk-1.0.0.dist-info/RECORD,,
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 DeepXL.ai
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.
@@ -1 +0,0 @@
1
- deepxl_python_sdk