authentasdk 0.2.3__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.
- authentasdk-0.2.3/PKG-INFO +903 -0
- authentasdk-0.2.3/README.md +886 -0
- authentasdk-0.2.3/pyproject.toml +3 -0
- authentasdk-0.2.3/setup.cfg +32 -0
- authentasdk-0.2.3/src/authenta/__init__.py +21 -0
- authentasdk-0.2.3/src/authenta/async_authenta_client.py +340 -0
- authentasdk-0.2.3/src/authenta/authenta_client.py +379 -0
- authentasdk-0.2.3/src/authenta/authenta_exceptions.py +74 -0
- authentasdk-0.2.3/src/authenta/face_intelligence.py +131 -0
- authentasdk-0.2.3/src/authenta/visualization.py +470 -0
- authentasdk-0.2.3/src/authentasdk.egg-info/PKG-INFO +903 -0
- authentasdk-0.2.3/src/authentasdk.egg-info/SOURCES.txt +14 -0
- authentasdk-0.2.3/src/authentasdk.egg-info/dependency_links.txt +1 -0
- authentasdk-0.2.3/src/authentasdk.egg-info/requires.txt +1 -0
- authentasdk-0.2.3/src/authentasdk.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,903 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: authentasdk
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: Python SDK for the Authenta API to detect deepfakes and manipulated media
|
|
5
|
+
Home-page: https://github.com/phospheneai/authenta-python-sdk
|
|
6
|
+
Author: Arjun Adhithya
|
|
7
|
+
Author-email: rrarjunadhithya@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Requires-Python: >=3.8
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: requests>=2.20.0
|
|
17
|
+
|
|
18
|
+
# Authenta Python SDK
|
|
19
|
+
|
|
20
|
+
Welcome to the official documentation for the **Authenta Python SDK** — your gateway to state-of-the-art deepfake detection, AI-image analysis, and face intelligence.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Table of Contents
|
|
25
|
+
|
|
26
|
+
1. [Getting Started](#1-getting-started)
|
|
27
|
+
2. [Models & Capabilities](#2-models--capabilities)
|
|
28
|
+
3. [Quick Start](#3-quick-start)
|
|
29
|
+
4. [Services](#4-services)
|
|
30
|
+
- [4.1 AC-1 — AI-Generated Image Detection](#41-ac-1--ai-generated-image-detection)
|
|
31
|
+
- [4.2 DF-1 — Deepfake Video Detection](#42-df-1--deepfake-video-detection)
|
|
32
|
+
- [4.3 FI-1 — Face Intelligence](#43-fi-1--face-intelligence)
|
|
33
|
+
- [4.4 Media Management](#44-media-management)
|
|
34
|
+
5. [Visualization](#5-visualization)
|
|
35
|
+
6. [Error Handling](#6-error-handling)
|
|
36
|
+
7. [API Reference](#7-api-reference)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 1. Getting Started
|
|
41
|
+
|
|
42
|
+
### Installation
|
|
43
|
+
|
|
44
|
+
**Option A: Install from PyPI (Recommended)**
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install authenta
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Option B: Local Development**
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
git clone https://github.com/phospheneai/authenta-python-sdk.git
|
|
54
|
+
cd authenta-python-sdk
|
|
55
|
+
pip install -e .
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Authentication & Initialization
|
|
59
|
+
|
|
60
|
+
**Synchronous Client**
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from authenta import AuthentaClient
|
|
64
|
+
|
|
65
|
+
client = AuthentaClient(
|
|
66
|
+
base_url="https://platform.authenta.ai",
|
|
67
|
+
client_id="YOUR_CLIENT_ID",
|
|
68
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Asynchronous Client**
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import asyncio
|
|
76
|
+
from authenta.async_authenta_client import AsyncAuthentaClient
|
|
77
|
+
|
|
78
|
+
async def main():
|
|
79
|
+
async with AsyncAuthentaClient(
|
|
80
|
+
base_url="https://platform.authenta.ai",
|
|
81
|
+
client_id="YOUR_CLIENT_ID",
|
|
82
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
83
|
+
) as client:
|
|
84
|
+
# use client here
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
asyncio.run(main())
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> The async client is a context manager (`async with`) that automatically manages the underlying HTTP session. You can also call `await client.aclose()` manually if you prefer.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 1.1 Why Use the Async Client?
|
|
95
|
+
|
|
96
|
+
The SDK ships two clients that are functionally identical — the difference is in how they handle waiting.
|
|
97
|
+
|
|
98
|
+
### Synchronous client (`AuthentaClient`)
|
|
99
|
+
|
|
100
|
+
The sync client blocks the calling thread while it waits for processing to complete. This is the right choice when:
|
|
101
|
+
|
|
102
|
+
- You are writing a **script**, a CLI tool, or a Jupyter notebook.
|
|
103
|
+
- Your workload is **sequential** — one file at a time, results needed before moving on.
|
|
104
|
+
- You are not running inside an async framework (FastAPI, aiohttp, etc.).
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
# Blocks here until the result is ready
|
|
108
|
+
media = client.process("photo.jpg", model_type="AC-1")
|
|
109
|
+
print(media["fake"])
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Async client (`AsyncAuthentaClient`)
|
|
113
|
+
|
|
114
|
+
The async client never blocks the event loop. While it is waiting for the API to finish processing, your application can continue doing other work. This is the right choice when:
|
|
115
|
+
|
|
116
|
+
- You are building a **web server** (FastAPI, Starlette, aiohttp) and need to keep handling other requests while waiting for results.
|
|
117
|
+
- You want to run **multiple detections in parallel** without spawning threads.
|
|
118
|
+
- You are already writing `async/await` code.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
# Submits both jobs concurrently — total wait ≈ max(t1, t2), not t1 + t2
|
|
122
|
+
results = await asyncio.gather(
|
|
123
|
+
client.process("photo1.jpg", model_type="AC-1"),
|
|
124
|
+
client.process("video1.mp4", model_type="DF-1"),
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Comparison
|
|
129
|
+
|
|
130
|
+
| | `AuthentaClient` | `AsyncAuthentaClient` |
|
|
131
|
+
| :-- | :-- | :-- |
|
|
132
|
+
| Blocks the thread while polling | Yes | No |
|
|
133
|
+
| Works without an event loop | Yes | No — needs `asyncio` |
|
|
134
|
+
| Concurrent requests | No (sequential) | Yes — via `asyncio.gather` |
|
|
135
|
+
| Best for | Scripts, notebooks, CLIs | Web servers, async apps |
|
|
136
|
+
| Import | `from authenta import AuthentaClient` | `from authenta.async_authenta_client import AsyncAuthentaClient` |
|
|
137
|
+
|
|
138
|
+
> **Rule of thumb:** if you're not sure which to use, start with the sync client. Switch to async when you need to serve multiple users simultaneously or run detections in parallel.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 2. Models & Capabilities
|
|
143
|
+
|
|
144
|
+
| Model | Modality | Capability |
|
|
145
|
+
| :-- | :-- | :-- |
|
|
146
|
+
| `AC-1` | Image | Detects AI-generated or manipulated images (Midjourney, Stable Diffusion, Photoshop, etc.) |
|
|
147
|
+
| `DF-1` | Video | Detects deepfake videos — face swaps, reenactments, and facial manipulations |
|
|
148
|
+
| `FI-1` | Image / Video | Face Intelligence — liveness detection, face swap detection, face similarity comparison |
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 3. Quick Start
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from authenta import AuthentaClient
|
|
156
|
+
|
|
157
|
+
client = AuthentaClient(
|
|
158
|
+
base_url="https://platform.authenta.ai",
|
|
159
|
+
client_id="YOUR_CLIENT_ID",
|
|
160
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Detect AI-generated image (blocks until result is ready)
|
|
164
|
+
media = client.process("photo.jpg", model_type="AC-1")
|
|
165
|
+
print(f"Status : {media['status']}")
|
|
166
|
+
print(f"Is Fake: {media.get('fake')}")
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 4. Services
|
|
172
|
+
|
|
173
|
+
### 4.1 AC-1 — AI-Generated Image Detection
|
|
174
|
+
|
|
175
|
+
Identify whether an image was created by generative AI or manipulated with editing tools.
|
|
176
|
+
|
|
177
|
+
#### Synchronous
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from authenta import AuthentaClient
|
|
181
|
+
|
|
182
|
+
client = AuthentaClient(
|
|
183
|
+
base_url="https://platform.authenta.ai",
|
|
184
|
+
client_id="YOUR_CLIENT_ID",
|
|
185
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# One-call: upload + wait for result
|
|
189
|
+
media = client.process("samples/photo.jpg", model_type="AC-1")
|
|
190
|
+
|
|
191
|
+
print(f"Media ID : {media['mid']}")
|
|
192
|
+
print(f"Status : {media['status']}")
|
|
193
|
+
print(f"Is Fake : {media.get('fake')}")
|
|
194
|
+
print(f"Result : {media.get('resultURL')}")
|
|
195
|
+
print(f"Heatmap : {media.get('heatmapURL')}")
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Two-step (upload now, poll later)**
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
# Step 1 — upload
|
|
202
|
+
upload_meta = client.upload_file("samples/photo.jpg", model_type="AC-1")
|
|
203
|
+
mid = upload_meta["mid"]
|
|
204
|
+
print(f"Uploaded. Media ID: {mid}")
|
|
205
|
+
|
|
206
|
+
# ... do other work ...
|
|
207
|
+
|
|
208
|
+
# Step 2 — wait for result
|
|
209
|
+
media = client.wait_for_media(mid)
|
|
210
|
+
print(f"Status : {media['status']}")
|
|
211
|
+
print(f"Is Fake: {media.get('fake')}")
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### Asynchronous
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
import asyncio
|
|
218
|
+
from authenta.async_authenta_client import AsyncAuthentaClient
|
|
219
|
+
|
|
220
|
+
async def detect_image():
|
|
221
|
+
async with AsyncAuthentaClient(
|
|
222
|
+
base_url="https://platform.authenta.ai",
|
|
223
|
+
client_id="YOUR_CLIENT_ID",
|
|
224
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
225
|
+
) as client:
|
|
226
|
+
# One-call: upload + wait
|
|
227
|
+
media = await client.process("samples/photo.jpg", model_type="AC-1")
|
|
228
|
+
print(f"Status : {media['status']}")
|
|
229
|
+
print(f"Is Fake: {media.get('fake')}")
|
|
230
|
+
|
|
231
|
+
asyncio.run(detect_image())
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Two-step async (upload now, poll later)**
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
async def detect_image_async():
|
|
238
|
+
async with AsyncAuthentaClient(...) as client:
|
|
239
|
+
# Step 1 — upload
|
|
240
|
+
upload_meta = await client.upload_file("samples/photo.jpg", model_type="AC-1")
|
|
241
|
+
mid = upload_meta["mid"]
|
|
242
|
+
|
|
243
|
+
# Step 2 — poll when ready
|
|
244
|
+
media = await client.wait_for_media(mid)
|
|
245
|
+
print(f"Status : {media['status']}")
|
|
246
|
+
print(f"Is Fake: {media.get('fake')}")
|
|
247
|
+
|
|
248
|
+
asyncio.run(detect_image_async())
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### 4.2 DF-1 — Deepfake Video Detection
|
|
254
|
+
|
|
255
|
+
Detect face swaps, reenactments, and other facial manipulations in video content.
|
|
256
|
+
|
|
257
|
+
#### Synchronous
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
from authenta import AuthentaClient
|
|
261
|
+
|
|
262
|
+
client = AuthentaClient(
|
|
263
|
+
base_url="https://platform.authenta.ai",
|
|
264
|
+
client_id="YOUR_CLIENT_ID",
|
|
265
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# One-call: upload + wait for result
|
|
269
|
+
media = client.process("samples/video.mp4", model_type="DF-1")
|
|
270
|
+
|
|
271
|
+
print(f"Media ID : {media['mid']}")
|
|
272
|
+
print(f"Status : {media['status']}")
|
|
273
|
+
print(f"Is Fake : {media.get('fake')}")
|
|
274
|
+
print(f"Participants: {len(media.get('participants', []))}")
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Two-step**
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
# Step 1 — upload
|
|
281
|
+
upload_meta = client.upload_file("samples/video.mp4", model_type="DF-1")
|
|
282
|
+
mid = upload_meta["mid"]
|
|
283
|
+
|
|
284
|
+
# Step 2 — poll with custom interval/timeout
|
|
285
|
+
media = client.wait_for_media(mid, interval=10.0, timeout=900.0)
|
|
286
|
+
print(f"Status : {media['status']}")
|
|
287
|
+
print(f"Is Fake: {media.get('fake')}")
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
#### Asynchronous
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
import asyncio
|
|
294
|
+
from authenta.async_authenta_client import AsyncAuthentaClient
|
|
295
|
+
|
|
296
|
+
async def detect_deepfake():
|
|
297
|
+
async with AsyncAuthentaClient(
|
|
298
|
+
base_url="https://platform.authenta.ai",
|
|
299
|
+
client_id="YOUR_CLIENT_ID",
|
|
300
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
301
|
+
) as client:
|
|
302
|
+
media = await client.process("samples/video.mp4", model_type="DF-1")
|
|
303
|
+
print(f"Status : {media['status']}")
|
|
304
|
+
print(f"Is Fake: {media.get('fake')}")
|
|
305
|
+
|
|
306
|
+
asyncio.run(detect_deepfake())
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Batch processing multiple videos (async)**
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
async def process_batch(video_paths: list):
|
|
313
|
+
async with AsyncAuthentaClient(...) as client:
|
|
314
|
+
tasks = [client.process(p, model_type="DF-1") for p in video_paths]
|
|
315
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
316
|
+
|
|
317
|
+
for path, result in zip(video_paths, results):
|
|
318
|
+
if isinstance(result, Exception):
|
|
319
|
+
print(f"[FAILED] {path}: {result}")
|
|
320
|
+
else:
|
|
321
|
+
print(f"[OK] {path}: fake={result.get('fake')}")
|
|
322
|
+
|
|
323
|
+
asyncio.run(process_batch(["video1.mp4", "video2.mp4", "video3.mp4"]))
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
### 4.3 FI-1 — Face Intelligence
|
|
329
|
+
|
|
330
|
+
Face Intelligence provides four detection capabilities. You can enable any combination of them in a single call.
|
|
331
|
+
|
|
332
|
+
| Parameter | Type | Modality | Description |
|
|
333
|
+
| :-- | :-- | :-- | :-- |
|
|
334
|
+
| `livenessCheck` | `bool` | Image / Video | Detect whether the face is real or a presentation attack |
|
|
335
|
+
| `faceswapCheck` | `bool` | **Video only** | Detect face-swap manipulation |
|
|
336
|
+
| `faceSimilarityCheck` | `bool` | **Image only** | Compare face against a reference image |
|
|
337
|
+
| `isSingleFace` | `bool` | Image / Video | Validate that only one face is present |
|
|
338
|
+
| `reference_img_path` | `str` | Image | Required when `faceSimilarityCheck=True` |
|
|
339
|
+
| `auto_polling` | `bool` | — | `True` (default): block until result ready. `False`: return upload metadata immediately |
|
|
340
|
+
|
|
341
|
+
#### Liveness Detection
|
|
342
|
+
|
|
343
|
+
**Synchronous**
|
|
344
|
+
|
|
345
|
+
```python
|
|
346
|
+
from authenta import AuthentaClient
|
|
347
|
+
|
|
348
|
+
client = AuthentaClient(
|
|
349
|
+
base_url="https://platform.authenta.ai",
|
|
350
|
+
client_id="YOUR_CLIENT_ID",
|
|
351
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
media = client.face_intelligence(
|
|
355
|
+
path="samples/face_video.mp4",
|
|
356
|
+
model_type="FI-1",
|
|
357
|
+
livenessCheck=True,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
print(f"Media ID : {media['mid']}")
|
|
361
|
+
print(f"Status : {media['status']}")
|
|
362
|
+
print(f"Liveness : {media.get('isLiveness')}")
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
**Asynchronous**
|
|
366
|
+
|
|
367
|
+
```python
|
|
368
|
+
import asyncio
|
|
369
|
+
from authenta.async_authenta_client import AsyncAuthentaClient
|
|
370
|
+
|
|
371
|
+
async def liveness():
|
|
372
|
+
async with AsyncAuthentaClient(
|
|
373
|
+
base_url="https://platform.authenta.ai",
|
|
374
|
+
client_id="YOUR_CLIENT_ID",
|
|
375
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
376
|
+
) as client:
|
|
377
|
+
media = await client.process_FI(
|
|
378
|
+
path="samples/face_video.mp4",
|
|
379
|
+
model_type="FI-1",
|
|
380
|
+
livenessCheck=True,
|
|
381
|
+
)
|
|
382
|
+
print(f"Status : {media['status']}")
|
|
383
|
+
print(f"Liveness : {media.get('isLiveness')}")
|
|
384
|
+
|
|
385
|
+
asyncio.run(liveness())
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
#### Face Swap Detection (Video Only)
|
|
391
|
+
|
|
392
|
+
**Synchronous**
|
|
393
|
+
|
|
394
|
+
```python
|
|
395
|
+
media = client.face_intelligence(
|
|
396
|
+
path="samples/face_video.mp4",
|
|
397
|
+
model_type="FI-1",
|
|
398
|
+
faceswapCheck=True,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
print(f"Status : {media['status']}")
|
|
402
|
+
print(f"Face Swap : {media.get('isDeepFake')}")
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
**Asynchronous**
|
|
406
|
+
|
|
407
|
+
```python
|
|
408
|
+
async def faceswap():
|
|
409
|
+
async with AsyncAuthentaClient(...) as client:
|
|
410
|
+
media = await client.process_FI(
|
|
411
|
+
path="samples/face_video.mp4",
|
|
412
|
+
model_type="FI-1",
|
|
413
|
+
faceSwapCheck=True,
|
|
414
|
+
)
|
|
415
|
+
print(f"Status : {media['status']}")
|
|
416
|
+
print(f"Face Swap : {media.get('isDeepFake')}")
|
|
417
|
+
|
|
418
|
+
asyncio.run(faceswap())
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
#### Face Similarity Check (Image Only)
|
|
424
|
+
|
|
425
|
+
Compare two faces and determine whether they belong to the same person.
|
|
426
|
+
|
|
427
|
+
**Synchronous**
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
media = client.face_intelligence(
|
|
431
|
+
path="samples/person_A.jpg",
|
|
432
|
+
model_type="FI-1",
|
|
433
|
+
faceSimilarityCheck=True,
|
|
434
|
+
reference_img_path="samples/person_B.jpg",
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
print(f"Status : {media['status']}")
|
|
438
|
+
print(f"Same Person : {media.get('isSimilar')}")
|
|
439
|
+
print(f"Similarity Score : {media.get('similarityScore')}")
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Asynchronous**
|
|
443
|
+
|
|
444
|
+
```python
|
|
445
|
+
async def similarity():
|
|
446
|
+
async with AsyncAuthentaClient(...) as client:
|
|
447
|
+
media = await client.process_FI(
|
|
448
|
+
path="samples/person_A.jpg",
|
|
449
|
+
model_type="FI-1",
|
|
450
|
+
faceSimilarityCheck=True,
|
|
451
|
+
)
|
|
452
|
+
print(f"Similar : {media.get('isSimilar')}")
|
|
453
|
+
print(f"Score : {media.get('similarityScore')}")
|
|
454
|
+
|
|
455
|
+
asyncio.run(similarity())
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
#### Manual Polling with `auto_polling=False`
|
|
461
|
+
|
|
462
|
+
By default, `face_intelligence()` and `process_FI()` block until processing is complete (`auto_polling=True`). Set `auto_polling=False` to return immediately after upload and poll manually — useful for web servers, background workers, or batched jobs.
|
|
463
|
+
|
|
464
|
+
**Synchronous**
|
|
465
|
+
|
|
466
|
+
```python
|
|
467
|
+
# Step 1 — fire upload, return immediately
|
|
468
|
+
upload_meta = client.face_intelligence(
|
|
469
|
+
path="samples/face_video.mp4",
|
|
470
|
+
model_type="FI-1",
|
|
471
|
+
livenessCheck=True,
|
|
472
|
+
auto_polling=False, # do not block
|
|
473
|
+
)
|
|
474
|
+
mid = upload_meta["mid"]
|
|
475
|
+
print(f"Upload started. Media ID: {mid}")
|
|
476
|
+
|
|
477
|
+
# ... do other work ...
|
|
478
|
+
|
|
479
|
+
# Step 2 — poll when ready
|
|
480
|
+
media = client.wait_for_media(mid, interval=5.0, timeout=600.0)
|
|
481
|
+
print(f"Status : {media['status']}")
|
|
482
|
+
print(f"Liveness : {media.get('isLiveness')}")
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
**Asynchronous**
|
|
486
|
+
|
|
487
|
+
```python
|
|
488
|
+
async def manual_poll():
|
|
489
|
+
async with AsyncAuthentaClient(...) as client:
|
|
490
|
+
# Step 1 — upload without blocking
|
|
491
|
+
upload_meta = await client.process_FI(
|
|
492
|
+
path="samples/face_video.mp4",
|
|
493
|
+
model_type="FI-1",
|
|
494
|
+
livenessCheck=True,
|
|
495
|
+
auto_polling=False,
|
|
496
|
+
)
|
|
497
|
+
mid = upload_meta["mid"]
|
|
498
|
+
|
|
499
|
+
# Step 2 — poll when ready
|
|
500
|
+
media = await client.wait_for_media(mid)
|
|
501
|
+
print(f"Status : {media['status']}")
|
|
502
|
+
print(f"Liveness : {media.get('isLiveness')}")
|
|
503
|
+
|
|
504
|
+
asyncio.run(manual_poll())
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
### 4.4 Media Management
|
|
510
|
+
|
|
511
|
+
#### Get Media
|
|
512
|
+
|
|
513
|
+
Retrieve the current state of a media record by its ID.
|
|
514
|
+
|
|
515
|
+
**Synchronous**
|
|
516
|
+
|
|
517
|
+
```python
|
|
518
|
+
media = client.get_media("YOUR_MEDIA_ID")
|
|
519
|
+
print(f"Status : {media['status']}")
|
|
520
|
+
print(f"Type : {media.get('type')}")
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
**Asynchronous**
|
|
524
|
+
|
|
525
|
+
```python
|
|
526
|
+
async def get():
|
|
527
|
+
async with AsyncAuthentaClient(...) as client:
|
|
528
|
+
media = await client.get_media("YOUR_MEDIA_ID")
|
|
529
|
+
print(f"Status : {media['status']}")
|
|
530
|
+
|
|
531
|
+
asyncio.run(get())
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
#### List Media
|
|
537
|
+
|
|
538
|
+
Retrieve a paginated list of all media records associated with your account.
|
|
539
|
+
|
|
540
|
+
**Synchronous**
|
|
541
|
+
|
|
542
|
+
```python
|
|
543
|
+
# All media (default page)
|
|
544
|
+
all_media = client.list_media()
|
|
545
|
+
print(f"Total records: {len(all_media.get('items', []))}")
|
|
546
|
+
|
|
547
|
+
# With pagination
|
|
548
|
+
page_2 = client.list_media(page=2, pageSize=20)
|
|
549
|
+
for item in page_2.get("items", []):
|
|
550
|
+
print(f" {item['mid']} — {item['status']}")
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
**Asynchronous**
|
|
554
|
+
|
|
555
|
+
```python
|
|
556
|
+
async def list_all():
|
|
557
|
+
async with AsyncAuthentaClient(...) as client:
|
|
558
|
+
all_media = await client.list_media(page=1, pageSize=50)
|
|
559
|
+
for item in all_media.get("items", []):
|
|
560
|
+
print(f" {item['mid']} — {item['status']}")
|
|
561
|
+
|
|
562
|
+
asyncio.run(list_all())
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
567
|
+
#### Delete Media
|
|
568
|
+
|
|
569
|
+
Permanently remove a media record and its associated data.
|
|
570
|
+
|
|
571
|
+
**Synchronous**
|
|
572
|
+
|
|
573
|
+
```python
|
|
574
|
+
client.delete_media("YOUR_MEDIA_ID")
|
|
575
|
+
print("Deleted.")
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
**Asynchronous**
|
|
579
|
+
|
|
580
|
+
```python
|
|
581
|
+
async def delete():
|
|
582
|
+
async with AsyncAuthentaClient(...) as client:
|
|
583
|
+
await client.delete_media("YOUR_MEDIA_ID")
|
|
584
|
+
print("Deleted.")
|
|
585
|
+
|
|
586
|
+
asyncio.run(delete())
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
---
|
|
590
|
+
|
|
591
|
+
#### Wait for Media (Manual Poll)
|
|
592
|
+
|
|
593
|
+
Poll a known media ID until processing completes. Useful after `upload_file()` or `face_intelligence(auto_polling=False)`.
|
|
594
|
+
|
|
595
|
+
**Synchronous**
|
|
596
|
+
|
|
597
|
+
```python
|
|
598
|
+
media = client.wait_for_media(
|
|
599
|
+
mid="YOUR_MEDIA_ID",
|
|
600
|
+
interval=5.0, # seconds between polls
|
|
601
|
+
timeout=600.0, # max wait time in seconds
|
|
602
|
+
)
|
|
603
|
+
print(f"Final status: {media['status']}")
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
**Asynchronous**
|
|
607
|
+
|
|
608
|
+
```python
|
|
609
|
+
async def poll():
|
|
610
|
+
async with AsyncAuthentaClient(...) as client:
|
|
611
|
+
media = await client.wait_for_media(
|
|
612
|
+
mid="YOUR_MEDIA_ID",
|
|
613
|
+
interval=5.0,
|
|
614
|
+
timeout=600.0,
|
|
615
|
+
)
|
|
616
|
+
print(f"Final status: {media['status']}")
|
|
617
|
+
|
|
618
|
+
asyncio.run(poll())
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## 5. Visualization
|
|
624
|
+
|
|
625
|
+
The SDK includes a `visualization` module to generate visual overlays for detection results.
|
|
626
|
+
|
|
627
|
+
### Heatmaps — AC-1 (Images)
|
|
628
|
+
|
|
629
|
+
```python
|
|
630
|
+
from authenta.visualization import save_heatmap
|
|
631
|
+
|
|
632
|
+
media = client.process("samples/photo.jpg", model_type="AC-1")
|
|
633
|
+
|
|
634
|
+
save_heatmap(
|
|
635
|
+
media=media,
|
|
636
|
+
out_path="results/heatmap.jpg",
|
|
637
|
+
model_type="AC-1",
|
|
638
|
+
)
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
Downloads the `heatmapURL` and saves an RGB overlay image showing manipulated regions.
|
|
642
|
+
|
|
643
|
+
---
|
|
644
|
+
|
|
645
|
+
### Heatmaps — DF-1 (Videos)
|
|
646
|
+
|
|
647
|
+
For DF-1, the API may return multiple participants (faces). One heatmap video is saved per participant.
|
|
648
|
+
|
|
649
|
+
```python
|
|
650
|
+
from authenta.visualization import save_heatmap
|
|
651
|
+
|
|
652
|
+
media = client.process("samples/video.mp4", model_type="DF-1")
|
|
653
|
+
|
|
654
|
+
# Pass a folder path; saves heatmap_p0.mp4, heatmap_p1.mp4, ...
|
|
655
|
+
save_heatmap(
|
|
656
|
+
media=media,
|
|
657
|
+
out_path="./results",
|
|
658
|
+
model_type="DF-1",
|
|
659
|
+
)
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
### Bounding Box Video — DF-1
|
|
665
|
+
|
|
666
|
+
Draw detection boxes around faces in a deepfake video and save an annotated copy.
|
|
667
|
+
|
|
668
|
+
```python
|
|
669
|
+
from authenta.visualization import save_bounding_box_video
|
|
670
|
+
|
|
671
|
+
media = client.process("samples/video.mp4", model_type="DF-1")
|
|
672
|
+
|
|
673
|
+
save_bounding_box_video(
|
|
674
|
+
media,
|
|
675
|
+
src_video_path="samples/video.mp4",
|
|
676
|
+
out_video_path="results/annotated_video.mp4",
|
|
677
|
+
)
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
Fetches bounding box data from `resultURL` and renders labels and confidence scores onto each frame using OpenCV.
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## 6. Error Handling
|
|
685
|
+
|
|
686
|
+
All SDK methods raise typed exceptions defined in `authenta_exceptions.py`.
|
|
687
|
+
|
|
688
|
+
| Exception | API Code | Cause |
|
|
689
|
+
| :-- | :-- | :-- |
|
|
690
|
+
| `AuthenticationError` | `IAM001` | Invalid or missing credentials |
|
|
691
|
+
| `AuthorizationError` | `IAM002` | Insufficient permissions |
|
|
692
|
+
| `QuotaExceededError` | `AA001` | API limit reached for your plan |
|
|
693
|
+
| `InsufficientCreditsError` | `U007` | Not enough credits |
|
|
694
|
+
| `ValidationError` | — | Bad request / unexpected response |
|
|
695
|
+
| `ServerError` | — | Server-side 5xx error |
|
|
696
|
+
| `AuthentaError` | — | Base class for all SDK errors |
|
|
697
|
+
|
|
698
|
+
```python
|
|
699
|
+
from authenta import AuthentaClient
|
|
700
|
+
from authenta import (
|
|
701
|
+
AuthentaError,
|
|
702
|
+
AuthenticationError,
|
|
703
|
+
AuthorizationError,
|
|
704
|
+
QuotaExceededError,
|
|
705
|
+
InsufficientCreditsError,
|
|
706
|
+
ValidationError,
|
|
707
|
+
ServerError,
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
client = AuthentaClient(
|
|
711
|
+
base_url="https://platform.authenta.ai",
|
|
712
|
+
client_id="YOUR_CLIENT_ID",
|
|
713
|
+
client_secret="YOUR_CLIENT_SECRET",
|
|
714
|
+
)
|
|
715
|
+
|
|
716
|
+
try:
|
|
717
|
+
media = client.process("samples/photo.jpg", model_type="AC-1")
|
|
718
|
+
except AuthenticationError:
|
|
719
|
+
print("Check your client_id and client_secret.")
|
|
720
|
+
except QuotaExceededError:
|
|
721
|
+
print("API quota exceeded. Upgrade your plan.")
|
|
722
|
+
except InsufficientCreditsError:
|
|
723
|
+
print("Not enough credits.")
|
|
724
|
+
except TimeoutError as e:
|
|
725
|
+
print(f"Processing timed out: {e}")
|
|
726
|
+
except AuthentaError as e:
|
|
727
|
+
print(f"Authenta error [{e.code}]: {e.message}")
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
The same exception classes are raised by `AsyncAuthentaClient`.
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
734
|
+
## 7. API Reference
|
|
735
|
+
|
|
736
|
+
### `AuthentaClient` (Synchronous)
|
|
737
|
+
|
|
738
|
+
#### `__init__(base_url, client_id, client_secret)`
|
|
739
|
+
|
|
740
|
+
```python
|
|
741
|
+
AuthentaClient(base_url: str, client_id: str, client_secret: str)
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
Initializes the synchronous client.
|
|
745
|
+
|
|
746
|
+
---
|
|
747
|
+
|
|
748
|
+
#### `process(path, model_type, interval=5.0, timeout=600.0) -> Dict`
|
|
749
|
+
|
|
750
|
+
High-level wrapper: upload + poll until complete.
|
|
751
|
+
|
|
752
|
+
| Parameter | Type | Default | Description |
|
|
753
|
+
| :-- | :-- | :-- | :-- |
|
|
754
|
+
| `path` | `str` | required | Local path to the media file |
|
|
755
|
+
| `model_type` | `str` | required | `"AC-1"` or `"DF-1"` |
|
|
756
|
+
| `interval` | `float` | `5.0` | Seconds between polls |
|
|
757
|
+
| `timeout` | `float` | `600.0` | Max wait time in seconds |
|
|
758
|
+
|
|
759
|
+
Returns the final processed media dict. Raises `TimeoutError` if `timeout` elapses.
|
|
760
|
+
|
|
761
|
+
---
|
|
762
|
+
|
|
763
|
+
#### `face_intelligence(path, model_type, *, reference_img_path=None, isSingleFace=True, faceswapCheck=False, livenessCheck=False, faceSimilarityCheck=False, auto_polling=True, interval=5.0, timeout=600.0) -> Dict`
|
|
764
|
+
|
|
765
|
+
High-level wrapper for the FI-1 Face Intelligence model.
|
|
766
|
+
|
|
767
|
+
| Parameter | Type | Default | Description |
|
|
768
|
+
| :-- | :-- | :-- | :-- |
|
|
769
|
+
| `path` | `str` | required | Local path to image or video |
|
|
770
|
+
| `model_type` | `str` | required | Use `"FI-1"` |
|
|
771
|
+
| `reference_img_path` | `str` | `None` | Required when `faceSimilarityCheck=True` |
|
|
772
|
+
| `isSingleFace` | `bool` | `True` | Validate only one face is present |
|
|
773
|
+
| `faceswapCheck` | `bool` | `False` | Face swap detection (video only) |
|
|
774
|
+
| `livenessCheck` | `bool` | `False` | Liveness verification |
|
|
775
|
+
| `faceSimilarityCheck` | `bool` | `False` | Face comparison (image only) |
|
|
776
|
+
| `auto_polling` | `bool` | `True` | `True`: block until done. `False`: return upload metadata immediately |
|
|
777
|
+
| `interval` | `float` | `5.0` | Seconds between polls (when `auto_polling=True`) |
|
|
778
|
+
| `timeout` | `float` | `600.0` | Max wait time (when `auto_polling=True`) |
|
|
779
|
+
|
|
780
|
+
Returns final media dict when `auto_polling=True`; initial upload metadata when `auto_polling=False`.
|
|
781
|
+
Raises `ValueError` for invalid combinations (e.g. `faceswapCheck=True` on an image).
|
|
782
|
+
|
|
783
|
+
---
|
|
784
|
+
|
|
785
|
+
#### `upload_file(path, model_type, **kwargs) -> Dict`
|
|
786
|
+
|
|
787
|
+
Two-step file upload: POST `/api/media` → PUT to S3 presigned URL.
|
|
788
|
+
|
|
789
|
+
| Parameter | Type | Description |
|
|
790
|
+
| :-- | :-- | :-- |
|
|
791
|
+
| `path` | `str` | Local path to the file |
|
|
792
|
+
| `model_type` | `str` | `"AC-1"`, `"DF-1"`, or `"FI-1"` |
|
|
793
|
+
|
|
794
|
+
Returns the initial media metadata dict (includes `mid`, `status`, `uploadUrl`).
|
|
795
|
+
|
|
796
|
+
---
|
|
797
|
+
|
|
798
|
+
#### `wait_for_media(mid, interval=5.0, timeout=600.0) -> Dict`
|
|
799
|
+
|
|
800
|
+
Poll `GET /api/media/{mid}` until terminal status (`PROCESSED`, `FAILED`, `ERROR`).
|
|
801
|
+
|
|
802
|
+
| Parameter | Type | Default | Description |
|
|
803
|
+
| :-- | :-- | :-- | :-- |
|
|
804
|
+
| `mid` | `str` | required | Media ID |
|
|
805
|
+
| `interval` | `float` | `5.0` | Seconds between polls |
|
|
806
|
+
| `timeout` | `float` | `600.0` | Max wait time in seconds |
|
|
807
|
+
|
|
808
|
+
Raises `TimeoutError` if `timeout` elapses.
|
|
809
|
+
|
|
810
|
+
---
|
|
811
|
+
|
|
812
|
+
#### `get_media(mid) -> Dict`
|
|
813
|
+
|
|
814
|
+
`GET /api/media/{mid}` — fetch the current state of a media record.
|
|
815
|
+
|
|
816
|
+
---
|
|
817
|
+
|
|
818
|
+
#### `list_media(**params) -> Dict`
|
|
819
|
+
|
|
820
|
+
`GET /api/media` — list all media records.
|
|
821
|
+
|
|
822
|
+
| Param | Description |
|
|
823
|
+
| :-- | :-- |
|
|
824
|
+
| `page` | Page number (1-based) |
|
|
825
|
+
| `pageSize` | Number of records per page |
|
|
826
|
+
|
|
827
|
+
---
|
|
828
|
+
|
|
829
|
+
#### `delete_media(mid) -> None`
|
|
830
|
+
|
|
831
|
+
`DELETE /api/media/{mid}` — permanently delete a media record.
|
|
832
|
+
|
|
833
|
+
---
|
|
834
|
+
|
|
835
|
+
### `AsyncAuthentaClient` (Asynchronous)
|
|
836
|
+
|
|
837
|
+
Mirrors `AuthentaClient` with `async/await`. Use as a context manager (`async with`) or call `await client.aclose()` when done.
|
|
838
|
+
|
|
839
|
+
#### `__init__(base_url, client_id, client_secret, *, timeout=30.0, client=None)`
|
|
840
|
+
|
|
841
|
+
```python
|
|
842
|
+
AsyncAuthentaClient(
|
|
843
|
+
base_url: str,
|
|
844
|
+
client_id: str,
|
|
845
|
+
client_secret: str,
|
|
846
|
+
timeout: float = 30.0, # httpx client timeout
|
|
847
|
+
client: httpx.AsyncClient = None # optional pre-built client
|
|
848
|
+
)
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
---
|
|
852
|
+
|
|
853
|
+
#### `await process(path, model_type, interval=5.0, timeout=600.0) -> Dict`
|
|
854
|
+
|
|
855
|
+
Async equivalent of `AuthentaClient.process()`.
|
|
856
|
+
|
|
857
|
+
---
|
|
858
|
+
|
|
859
|
+
#### `await process_FI(path, model_type, *, isSingleFace=None, faceSwapCheck=None, livenessCheck=None, faceSimilarityCheck=None, auto_polling=True, interval=5.0, timeout=600.0) -> Dict`
|
|
860
|
+
|
|
861
|
+
Async equivalent of `AuthentaClient.face_intelligence()`.
|
|
862
|
+
|
|
863
|
+
| Parameter | Type | Default | Description |
|
|
864
|
+
| :-- | :-- | :-- | :-- |
|
|
865
|
+
| `path` | `str` | required | Local path to image or video |
|
|
866
|
+
| `model_type` | `str` | required | Use `"FI-1"` |
|
|
867
|
+
| `isSingleFace` | `bool` | `None` | Validate single face |
|
|
868
|
+
| `faceSwapCheck` | `bool` | `None` | Face swap detection (video only) |
|
|
869
|
+
| `livenessCheck` | `bool` | `None` | Liveness verification |
|
|
870
|
+
| `faceSimilarityCheck` | `bool` | `None` | Face comparison (image only) |
|
|
871
|
+
| `auto_polling` | `bool` | `True` | `True`: await until done. `False`: return upload metadata immediately |
|
|
872
|
+
| `interval` | `float` | `5.0` | Seconds between polls |
|
|
873
|
+
| `timeout` | `float` | `600.0` | Max wait time in seconds |
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
877
|
+
#### `await upload_file(path, model_type, **kwargs) -> Dict`
|
|
878
|
+
|
|
879
|
+
Async two-step upload. Returns initial media metadata.
|
|
880
|
+
|
|
881
|
+
---
|
|
882
|
+
|
|
883
|
+
#### `await wait_for_media(mid, interval=5.0, timeout=600.0) -> Dict`
|
|
884
|
+
|
|
885
|
+
Async poll until terminal status. Raises `TimeoutError` on timeout.
|
|
886
|
+
|
|
887
|
+
---
|
|
888
|
+
|
|
889
|
+
#### `await get_media(mid) -> Dict`
|
|
890
|
+
|
|
891
|
+
Async fetch of a single media record.
|
|
892
|
+
|
|
893
|
+
---
|
|
894
|
+
|
|
895
|
+
#### `await list_media(**params) -> Dict`
|
|
896
|
+
|
|
897
|
+
Async list of media records.
|
|
898
|
+
|
|
899
|
+
---
|
|
900
|
+
|
|
901
|
+
#### `await delete_media(mid) -> None`
|
|
902
|
+
|
|
903
|
+
Async delete of a media record.
|