deepxl-python-sdk 1.0.1__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 +49 -0
- deepxl/client.py +278 -0
- deepxl/types.py +205 -0
- deepxl_python_sdk-1.2.1.dist-info/METADATA +326 -0
- deepxl_python_sdk-1.2.1.dist-info/RECORD +7 -0
- {deepxl_python_sdk-1.0.1.dist-info → deepxl_python_sdk-1.2.1.dist-info}/WHEEL +1 -1
- deepxl_python_sdk-1.2.1.dist-info/top_level.txt +1 -0
- deepxl_python_sdk/__init__.py +0 -9
- deepxl_python_sdk/client.py +0 -179
- deepxl_python_sdk/error.py +0 -5
- deepxl_python_sdk/mimetypes.py +0 -36
- deepxl_python_sdk-1.0.1.dist-info/METADATA +0 -92
- deepxl_python_sdk-1.0.1.dist-info/RECORD +0 -9
- deepxl_python_sdk-1.0.1.dist-info/licenses/LICENSE +0 -21
- deepxl_python_sdk-1.0.1.dist-info/top_level.txt +0 -1
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,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
deepxl
|
deepxl_python_sdk/__init__.py
DELETED
deepxl_python_sdk/client.py
DELETED
|
@@ -1,179 +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
|
-
"""Initialize the DeepXL client with the given API key.
|
|
61
|
-
args:
|
|
62
|
-
api_key (str): The API key to use for authentication.
|
|
63
|
-
"""
|
|
64
|
-
self.api_key = api_key
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def check_usage(self):
|
|
68
|
-
"""Return the usage and limits of the account."""
|
|
69
|
-
res = requests.get(
|
|
70
|
-
URL + "v1/account/",
|
|
71
|
-
headers={ "x-api-key": self.api_key },
|
|
72
|
-
timeout=5.0
|
|
73
|
-
)
|
|
74
|
-
try:
|
|
75
|
-
if res.status_code == 200:
|
|
76
|
-
json = res.json()
|
|
77
|
-
return UsageResponse(
|
|
78
|
-
json["imageUsageLimit"],
|
|
79
|
-
json["imageUsage"],
|
|
80
|
-
json["videoUsageLimit"],
|
|
81
|
-
json["videoUsage"],
|
|
82
|
-
json["audioUsageLimit"],
|
|
83
|
-
json["audioUsage"],
|
|
84
|
-
json["documentUsageLimit"],
|
|
85
|
-
json["documentUsage"]
|
|
86
|
-
)
|
|
87
|
-
else:
|
|
88
|
-
handle_http_error(res)
|
|
89
|
-
except ConnectionError as e:
|
|
90
|
-
raise e
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def analyze(self, model_name: str, file_name: str, file_data: bytes):
|
|
94
|
-
"""Analyze file data with the given model and return the result.
|
|
95
|
-
|
|
96
|
-
args:
|
|
97
|
-
model_name (str): The name of the model to use for analysis.
|
|
98
|
-
file_name (str): The name of the file to analyze.
|
|
99
|
-
file_data (bytes): The file data to analyze.
|
|
100
|
-
returns:
|
|
101
|
-
AnalysisResponse: The analysis result.
|
|
102
|
-
"""
|
|
103
|
-
if (len(file_data) == 0):
|
|
104
|
-
raise DeepXLError("File data is missing or invalid.")
|
|
105
|
-
try:
|
|
106
|
-
file_type = get_mimetype(file_name)
|
|
107
|
-
res = requests.post(
|
|
108
|
-
URL + "v1/analysis",
|
|
109
|
-
headers={
|
|
110
|
-
"x-api-key": self.api_key,
|
|
111
|
-
},
|
|
112
|
-
data={
|
|
113
|
-
"model": model_name
|
|
114
|
-
},
|
|
115
|
-
files={
|
|
116
|
-
"file": (file_name, file_data, file_type)
|
|
117
|
-
},
|
|
118
|
-
timeout=5.0
|
|
119
|
-
)
|
|
120
|
-
if res.status_code == 200:
|
|
121
|
-
result = res.json()["result"]
|
|
122
|
-
return AnalysisResponse(
|
|
123
|
-
likelihood=result["likelihood"],
|
|
124
|
-
reasoning=result["reasoning"],
|
|
125
|
-
model_results=result["modelResults"]
|
|
126
|
-
)
|
|
127
|
-
else:
|
|
128
|
-
handle_http_error(res)
|
|
129
|
-
except ConnectionError as e:
|
|
130
|
-
raise e
|
|
131
|
-
except DeepXLError as e:
|
|
132
|
-
raise e
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def analyze_file(self, model_name: str, file: str):
|
|
136
|
-
"""Analyze a file witht the given model and return the result.
|
|
137
|
-
args:
|
|
138
|
-
model_name (str): The name of the model to use for analysis.
|
|
139
|
-
file (str): The path to the file to analyze.
|
|
140
|
-
returns:
|
|
141
|
-
AnalysisResponse: The analysis result.
|
|
142
|
-
"""
|
|
143
|
-
f = None
|
|
144
|
-
try:
|
|
145
|
-
f = open(file, "rb")
|
|
146
|
-
base_name = file.split(r"[\\/]+")[-1]
|
|
147
|
-
file_type = get_mimetype(file)
|
|
148
|
-
res = requests.post(
|
|
149
|
-
URL + "v1/analysis",
|
|
150
|
-
headers={
|
|
151
|
-
"x-api-key": self.api_key,
|
|
152
|
-
},
|
|
153
|
-
data={
|
|
154
|
-
"model": model_name
|
|
155
|
-
},
|
|
156
|
-
files={
|
|
157
|
-
"file": (base_name, f, file_type)
|
|
158
|
-
},
|
|
159
|
-
timeout=5.0
|
|
160
|
-
)
|
|
161
|
-
f.close()
|
|
162
|
-
if res.status_code == 200:
|
|
163
|
-
result = res.json()["result"]
|
|
164
|
-
return AnalysisResponse(
|
|
165
|
-
likelihood=result["likelihood"],
|
|
166
|
-
reasoning=result["reasoning"],
|
|
167
|
-
model_results=result["modelResults"]
|
|
168
|
-
)
|
|
169
|
-
else:
|
|
170
|
-
handle_http_error(res)
|
|
171
|
-
except ConnectionError as e:
|
|
172
|
-
if not f.closed:
|
|
173
|
-
f.close()
|
|
174
|
-
raise e
|
|
175
|
-
except FileNotFoundError as e:
|
|
176
|
-
raise DeepXLError(f'File "{file}" does not exist.')
|
|
177
|
-
except DeepXLError as e:
|
|
178
|
-
raise e
|
|
179
|
-
|
deepxl_python_sdk/error.py
DELETED
deepxl_python_sdk/mimetypes.py
DELETED
|
@@ -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.1
|
|
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=9cm7eNXOrKyQP4Iv8xVR4PT0T2IkGTSpda-teWttmzk,5722
|
|
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.1.dist-info/licenses/LICENSE,sha256=im3EHYsOJNyBv1TGpEPlVoa1gPzRiydDr3tRDUVDP_s,1087
|
|
6
|
-
deepxl_python_sdk-1.0.1.dist-info/METADATA,sha256=eqwwj5IpRpqZdrxoOErSC9VhwRkkLTqEn7Cw4PCaQ1w,2756
|
|
7
|
-
deepxl_python_sdk-1.0.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
8
|
-
deepxl_python_sdk-1.0.1.dist-info/top_level.txt,sha256=X1AYAPOdVnNRxDCBdmESz-kPg1hIPAenR9WM2nBWzMQ,18
|
|
9
|
-
deepxl_python_sdk-1.0.1.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
|