deepxl-python-sdk 1.0.0__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.
- deepxl_python_sdk-1.0.0/LICENSE +21 -0
- deepxl_python_sdk-1.0.0/PKG-INFO +92 -0
- deepxl_python_sdk-1.0.0/README.md +77 -0
- deepxl_python_sdk-1.0.0/pyproject.toml +23 -0
- deepxl_python_sdk-1.0.0/setup.cfg +4 -0
- deepxl_python_sdk-1.0.0/src/deepxl_python_sdk/__init__.py +9 -0
- deepxl_python_sdk-1.0.0/src/deepxl_python_sdk/client.py +158 -0
- deepxl_python_sdk-1.0.0/src/deepxl_python_sdk/error.py +5 -0
- deepxl_python_sdk-1.0.0/src/deepxl_python_sdk/mimetypes.py +36 -0
- deepxl_python_sdk-1.0.0/src/deepxl_python_sdk.egg-info/PKG-INFO +92 -0
- deepxl_python_sdk-1.0.0/src/deepxl_python_sdk.egg-info/SOURCES.txt +12 -0
- deepxl_python_sdk-1.0.0/src/deepxl_python_sdk.egg-info/dependency_links.txt +1 -0
- deepxl_python_sdk-1.0.0/src/deepxl_python_sdk.egg-info/top_level.txt +1 -0
- deepxl_python_sdk-1.0.0/test/test_client.py +102 -0
|
@@ -0,0 +1,21 @@
|
|
|
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.
|
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# deepxl-python-sdk
|
|
2
|
+
Python Software Development Kit for DeepXL fraud detection services
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
|
|
6
|
+
Install the SDK using pip
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install deepxl-python-sdk
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Example
|
|
13
|
+
|
|
14
|
+
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.
|
|
15
|
+
|
|
16
|
+
Treat this API key like you would any environment secret. Do not commit to a public repository or store in plain text.
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from deepxl-python-sdk import DeepXLClient
|
|
20
|
+
|
|
21
|
+
client = new DeepXLClient(MY_API_KEY)
|
|
22
|
+
|
|
23
|
+
analysis_result = client.analyze_file("documents-model", ".\\file.pdf")
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Client methods
|
|
27
|
+
|
|
28
|
+
### check_usage
|
|
29
|
+
Returns the monthly usage quota and current usage for the payment period for each media type.
|
|
30
|
+
|
|
31
|
+
#### Returns:
|
|
32
|
+
|
|
33
|
+
Returns a ```UsageResponse``` object with the following properties:
|
|
34
|
+
|
|
35
|
+
|Property|Type|
|
|
36
|
+
|----|----|
|
|
37
|
+
|image_usage_limit|int|
|
|
38
|
+
|image_usage|int|
|
|
39
|
+
|video_usage_limit|int|
|
|
40
|
+
|video_usage|int|
|
|
41
|
+
|audio_usage_limit|int|
|
|
42
|
+
|audio_usage|int|
|
|
43
|
+
|document_usage_limit|int|
|
|
44
|
+
|document_usage|int|
|
|
45
|
+
|
|
46
|
+
### analyze
|
|
47
|
+
|
|
48
|
+
Analyze file data with DeepXL fraud detection.
|
|
49
|
+
|
|
50
|
+
#### Inputs
|
|
51
|
+
|
|
52
|
+
- **model_name:** the name of the model to use. You can find a complete list in our docs.
|
|
53
|
+
- **file_name:** the name of the file to analyze
|
|
54
|
+
- **file_data**: byte array of file data to analyze
|
|
55
|
+
|
|
56
|
+
> 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.
|
|
57
|
+
|
|
58
|
+
### analyze_file
|
|
59
|
+
|
|
60
|
+
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.
|
|
61
|
+
|
|
62
|
+
#### Inputs
|
|
63
|
+
|
|
64
|
+
- **model_name:** the name of the model to use. You can find a complete list in our docs.
|
|
65
|
+
- **file:** path of the file to analyze
|
|
66
|
+
|
|
67
|
+
#### Returns
|
|
68
|
+
|
|
69
|
+
Both ```analyze``` and ```analyze_file``` return an ```AnalysisResult``` object with the following properties:
|
|
70
|
+
|
|
71
|
+
| Property | Type | Description |
|
|
72
|
+
|----------|------|-|
|
|
73
|
+
|likelihood|float|The percent likelihood that the file has been manipulated|
|
|
74
|
+
|reasoning|str[]|model reasoning|
|
|
75
|
+
|model_results|dict|model-specific outputs|
|
|
76
|
+
|
|
77
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "deepxl-python-sdk"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name="deepxl", email="david@deepxl.ai" },
|
|
6
|
+
]
|
|
7
|
+
description = "Python Software Development Kit for DeepXL AI Fraud Detection Services"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.9"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"Operating System :: OS Independent",
|
|
13
|
+
]
|
|
14
|
+
license = "MIT"
|
|
15
|
+
license-files = ["LICEN[CS]E*"]
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["setuptools >= 77"]
|
|
19
|
+
build-backend = "setuptools.build_meta"
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://deepxl.ai"
|
|
23
|
+
Issues = "https://github.com/deepxl/python-sdk"
|
|
@@ -0,0 +1,158 @@
|
|
|
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
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/deepxl_python_sdk/__init__.py
|
|
5
|
+
src/deepxl_python_sdk/client.py
|
|
6
|
+
src/deepxl_python_sdk/error.py
|
|
7
|
+
src/deepxl_python_sdk/mimetypes.py
|
|
8
|
+
src/deepxl_python_sdk.egg-info/PKG-INFO
|
|
9
|
+
src/deepxl_python_sdk.egg-info/SOURCES.txt
|
|
10
|
+
src/deepxl_python_sdk.egg-info/dependency_links.txt
|
|
11
|
+
src/deepxl_python_sdk.egg-info/top_level.txt
|
|
12
|
+
test/test_client.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
deepxl_python_sdk
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from deepxl_python_sdk import DeepXLClient, UsageResponse, AnalysisResponse, DeepXLError
|
|
2
|
+
import unittest
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
API_KEY = os.environ['TESTING_API_KEY']
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestClient(unittest.TestCase):
|
|
10
|
+
|
|
11
|
+
def test_check_usage(self):
|
|
12
|
+
client = DeepXLClient(API_KEY)
|
|
13
|
+
response = client.check_usage()
|
|
14
|
+
self.assertIsInstance(response, UsageResponse)
|
|
15
|
+
self.assertTrue(response.image_usage_limit is not None)
|
|
16
|
+
self.assertTrue(response.image_usage is not None)
|
|
17
|
+
self.assertTrue(response.video_usage_limit is not None)
|
|
18
|
+
self.assertTrue(response.video_usage is not None)
|
|
19
|
+
self.assertTrue(response.audio_usage_limit is not None)
|
|
20
|
+
self.assertTrue(response.audio_usage is not None)
|
|
21
|
+
self.assertTrue(response.document_usage_limit is not None)
|
|
22
|
+
self.assertTrue(response.document_usage is not None)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_analyze(self):
|
|
26
|
+
client = DeepXLClient(API_KEY)
|
|
27
|
+
f = open(".\\test\\rickroll.jpg", 'rb')
|
|
28
|
+
data = f.read()
|
|
29
|
+
f.close()
|
|
30
|
+
response = client.analyze("always-false", "rickroll.jpg", data)
|
|
31
|
+
self.assertIsInstance(response, AnalysisResponse)
|
|
32
|
+
self.assertTrue(response.likelihood is not None)
|
|
33
|
+
self.assertTrue(response.reasoning is not None)
|
|
34
|
+
self.assertTrue(response.model_results is not None)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_analyze_file(self):
|
|
38
|
+
client = DeepXLClient(API_KEY)
|
|
39
|
+
response = client.analyze_file("always-true", ".\\test\\rickroll.jpg")
|
|
40
|
+
print(response)
|
|
41
|
+
self.assertIsInstance(response, AnalysisResponse)
|
|
42
|
+
self.assertTrue(response.likelihood is not None)
|
|
43
|
+
self.assertTrue(response.reasoning is not None)
|
|
44
|
+
self.assertTrue(response.model_results is not None)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_unauthorized(self):
|
|
48
|
+
client = DeepXLClient("bad123")
|
|
49
|
+
try:
|
|
50
|
+
response = client.check_usage()
|
|
51
|
+
except Exception as e:
|
|
52
|
+
self.assertIsInstance(e, DeepXLError)
|
|
53
|
+
self.assertEqual(e.message, "Invalid API key.")
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
response = client.analyze_file("always-true", "C:\\Users\\David\\Pictures\\rickroll.jpg")
|
|
57
|
+
except Exception as e:
|
|
58
|
+
self.assertIsInstance(e, DeepXLError)
|
|
59
|
+
self.assertEqual(e.message, "Invalid API key.")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_invalid_model_name(self):
|
|
63
|
+
client = DeepXLClient(API_KEY)
|
|
64
|
+
model_name = "not-a-model"
|
|
65
|
+
try:
|
|
66
|
+
f = open(".\\test\\rickroll.jpg", 'rb')
|
|
67
|
+
data = f.read()
|
|
68
|
+
f.close()
|
|
69
|
+
response = client.analyze(model_name, "rickroll.jpg", data)
|
|
70
|
+
except Exception as e:
|
|
71
|
+
self.assertIsInstance(e, DeepXLError)
|
|
72
|
+
self.assertEqual(e.message, f"Invalid model: {model_name}")
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
response = client.analyze_file(model_name, ".\\test\\rickroll.jpg")
|
|
76
|
+
except Exception as e:
|
|
77
|
+
self.assertIsInstance(e, DeepXLError)
|
|
78
|
+
self.assertEqual(e.message, f"Invalid model: {model_name}")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_no_file_data(self):
|
|
82
|
+
client = DeepXLClient(API_KEY)
|
|
83
|
+
try:
|
|
84
|
+
response = client.analyze("always-true", "rickroll.jpg", b"")
|
|
85
|
+
except Exception as e:
|
|
86
|
+
self.assertIsInstance(e, DeepXLError)
|
|
87
|
+
self.assertEqual(e.message, "File data is missing or invalid.")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_file_not_found(self):
|
|
91
|
+
client = DeepXLClient(API_KEY)
|
|
92
|
+
file = ".\\file\\not\\here.png"
|
|
93
|
+
try:
|
|
94
|
+
response = client.analyze_file("always-true", file)
|
|
95
|
+
except Exception as e:
|
|
96
|
+
self.assertIsInstance(e, DeepXLError)
|
|
97
|
+
self.assertEqual(e.message, f'File "{file}" does not exist.')
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == '__main__':
|
|
101
|
+
unittest.main()
|
|
102
|
+
|