authentasdk 0.2.3__tar.gz → 0.2.5__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 → authentasdk-0.2.5}/PKG-INFO +1 -1
- {authentasdk-0.2.3 → authentasdk-0.2.5}/setup.cfg +1 -1
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authenta/authenta_client.py +59 -44
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authentasdk.egg-info/PKG-INFO +1 -1
- {authentasdk-0.2.3 → authentasdk-0.2.5}/README.md +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/pyproject.toml +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authenta/__init__.py +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authenta/async_authenta_client.py +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authenta/authenta_exceptions.py +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authenta/face_intelligence.py +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authenta/visualization.py +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authentasdk.egg-info/SOURCES.txt +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authentasdk.egg-info/dependency_links.txt +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authentasdk.egg-info/requires.txt +0 -0
- {authentasdk-0.2.3 → authentasdk-0.2.5}/src/authentasdk.egg-info/top_level.txt +0 -0
|
@@ -22,7 +22,6 @@ from .authenta_exceptions import (
|
|
|
22
22
|
ValidationError,
|
|
23
23
|
ServerError,
|
|
24
24
|
)
|
|
25
|
-
from curl_cffi import requests as cffi_requests
|
|
26
25
|
|
|
27
26
|
def _raise_for_authenta_error(resp: requests.Response) -> None:
|
|
28
27
|
"""
|
|
@@ -35,7 +34,6 @@ def _raise_for_authenta_error(resp: requests.Response) -> None:
|
|
|
35
34
|
try:
|
|
36
35
|
data = resp.json()
|
|
37
36
|
except ValueError:
|
|
38
|
-
# Non-JSON error body
|
|
39
37
|
if 400 <= status < 500:
|
|
40
38
|
raise ValidationError(
|
|
41
39
|
message=resp.text or "Client error",
|
|
@@ -145,13 +143,12 @@ class AuthentaClient:
|
|
|
145
143
|
content_type: MIME type of the file (e.g. "image/png", "video/mp4").
|
|
146
144
|
size: File size in bytes.
|
|
147
145
|
model_type: Detection model type, e.g. "AC-1" or "DF-1".
|
|
148
|
-
"AC-1" - Image, "DF-1" - Video.
|
|
149
146
|
|
|
150
147
|
Returns:
|
|
151
148
|
Parsed JSON response containing at least 'mid' and 'uploadUrl'.
|
|
152
149
|
"""
|
|
153
150
|
url = f"{self.base_url}/api/media"
|
|
154
|
-
|
|
151
|
+
|
|
155
152
|
payload = {
|
|
156
153
|
"name": name,
|
|
157
154
|
"contentType": content_type,
|
|
@@ -167,21 +164,14 @@ class AuthentaClient:
|
|
|
167
164
|
"faceSimilarityCheck": kwargs.get("faceSimilarityCheck"),
|
|
168
165
|
}
|
|
169
166
|
payload.update({
|
|
170
|
-
"metadata": {
|
|
171
|
-
i: j for i, j in fi_params.items()
|
|
172
|
-
}
|
|
167
|
+
"metadata": {i: j for i, j in fi_params.items()}
|
|
173
168
|
})
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
else:
|
|
177
|
-
resp = requests.post(url, json=payload, headers=self._headers(), timeout=30)
|
|
178
|
-
print(f"create_media payload: {payload}")
|
|
179
|
-
print("create_media raw:", resp.status_code, repr(resp.text[:200]))
|
|
169
|
+
|
|
170
|
+
resp = requests.post(url, json=payload, headers=self._headers(), timeout=30)
|
|
180
171
|
if not resp.ok:
|
|
181
172
|
_raise_for_authenta_error(resp)
|
|
182
173
|
return _safe_json(resp)
|
|
183
174
|
|
|
184
|
-
|
|
185
175
|
def get_media(self, mid: str) -> Dict[str, Any]:
|
|
186
176
|
"""
|
|
187
177
|
GET /api/media/{mid}: fetch a single media record.
|
|
@@ -193,10 +183,7 @@ class AuthentaClient:
|
|
|
193
183
|
Parsed JSON media record.
|
|
194
184
|
"""
|
|
195
185
|
url = f"{self.base_url}/api/media/{mid}"
|
|
196
|
-
|
|
197
|
-
resp = cffi_requests.get(url, headers=self._headers(), impersonate="chrome", timeout=30)
|
|
198
|
-
else:
|
|
199
|
-
resp = requests.get(url, headers=self._headers(), timeout=30)
|
|
186
|
+
resp = requests.get(url, headers=self._headers(), timeout=30)
|
|
200
187
|
if not resp.ok:
|
|
201
188
|
_raise_for_authenta_error(resp)
|
|
202
189
|
return _safe_json(resp)
|
|
@@ -212,7 +199,6 @@ class AuthentaClient:
|
|
|
212
199
|
Args:
|
|
213
200
|
path: Local path to the media file.
|
|
214
201
|
model_type: Detection model type to use, e.g. "AC-1" or "DF-1".
|
|
215
|
-
**kwargs: Additional parameters for the media creation request.
|
|
216
202
|
|
|
217
203
|
Returns:
|
|
218
204
|
The JSON response from POST /api/media (includes 'mid', 'status', etc.).
|
|
@@ -221,7 +207,6 @@ class AuthentaClient:
|
|
|
221
207
|
content_type = self._content_type(path)
|
|
222
208
|
size = os.path.getsize(path)
|
|
223
209
|
|
|
224
|
-
# Step 1: create media
|
|
225
210
|
meta = self.create_media(
|
|
226
211
|
name=filename,
|
|
227
212
|
content_type=content_type,
|
|
@@ -233,7 +218,6 @@ class AuthentaClient:
|
|
|
233
218
|
if not upload_url:
|
|
234
219
|
raise RuntimeError("No uploadUrl in create_media response")
|
|
235
220
|
|
|
236
|
-
# Step 2: upload to S3
|
|
237
221
|
with open(path, "rb") as f:
|
|
238
222
|
put_resp = requests.put(
|
|
239
223
|
upload_url,
|
|
@@ -241,6 +225,7 @@ class AuthentaClient:
|
|
|
241
225
|
headers={"Content-Type": content_type},
|
|
242
226
|
timeout=300,
|
|
243
227
|
)
|
|
228
|
+
|
|
244
229
|
if model_type.upper() == "FI-1":
|
|
245
230
|
reference_img_url = meta.get("referenceUploadUrl")
|
|
246
231
|
if reference_img_url:
|
|
@@ -252,6 +237,7 @@ class AuthentaClient:
|
|
|
252
237
|
timeout=300,
|
|
253
238
|
)
|
|
254
239
|
ref_res.raise_for_status()
|
|
240
|
+
|
|
255
241
|
put_resp.raise_for_status()
|
|
256
242
|
return meta
|
|
257
243
|
|
|
@@ -286,10 +272,7 @@ class AuthentaClient:
|
|
|
286
272
|
Accepts optional query params (page, pageSize, filters) if the API supports them.
|
|
287
273
|
"""
|
|
288
274
|
url = f"{self.base_url}/api/media"
|
|
289
|
-
|
|
290
|
-
resp = cffi_requests.get(url, headers=self._headers(), params=params, impersonate="chrome", timeout=30)
|
|
291
|
-
else:
|
|
292
|
-
resp = requests.get(url, headers=self._headers(), params=params, timeout=30)
|
|
275
|
+
resp = requests.get(url, headers=self._headers(), params=params, timeout=30)
|
|
293
276
|
if not resp.ok:
|
|
294
277
|
_raise_for_authenta_error(resp)
|
|
295
278
|
return _safe_json(resp)
|
|
@@ -311,7 +294,34 @@ class AuthentaClient:
|
|
|
311
294
|
if not mid:
|
|
312
295
|
raise RuntimeError("No 'mid' in upload response")
|
|
313
296
|
return self.wait_for_media(mid, interval=interval, timeout=timeout)
|
|
314
|
-
|
|
297
|
+
|
|
298
|
+
def get_result(self, media: Dict[str, Any]) -> Dict[str, Any]:
|
|
299
|
+
"""
|
|
300
|
+
Fetch the detection result JSON from the media's resultURL.
|
|
301
|
+
|
|
302
|
+
The resultURL is a presigned S3 URL returned after processing.
|
|
303
|
+
It contains the actual detection output (e.g. isLiveness, isDeepFake,
|
|
304
|
+
isSimilar, similarityScore, etc.).
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
media: A media dict returned by face_intelligence(), process(), or
|
|
308
|
+
wait_for_media() — must contain a 'resultURL' key.
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
Parsed detection result dict from resultURL.
|
|
312
|
+
|
|
313
|
+
Raises:
|
|
314
|
+
ValueError: If the media dict has no resultURL.
|
|
315
|
+
RuntimeError: If the resultURL fetch fails.
|
|
316
|
+
"""
|
|
317
|
+
result_url = media.get("resultURL")
|
|
318
|
+
if not result_url:
|
|
319
|
+
raise ValueError("media dict has no 'resultURL'. Ensure processing is complete (status=PROCESSED).")
|
|
320
|
+
resp = requests.get(result_url, timeout=30)
|
|
321
|
+
if not resp.ok:
|
|
322
|
+
raise RuntimeError(f"Failed to fetch resultURL: HTTP {resp.status_code}")
|
|
323
|
+
return resp.json()
|
|
324
|
+
|
|
315
325
|
def face_intelligence(
|
|
316
326
|
self,
|
|
317
327
|
path: str,
|
|
@@ -329,36 +339,42 @@ class AuthentaClient:
|
|
|
329
339
|
High-level helper for Face Integrity (FI) model:
|
|
330
340
|
1) upload_file(path, model_type) -> get mid
|
|
331
341
|
2) wait_for_media(mid) (only if auto_polling=True)
|
|
342
|
+
3) get_result(media) to fetch detection output (only if auto_polling=True)
|
|
343
|
+
|
|
332
344
|
Args:
|
|
333
345
|
path: Local path to the media file.
|
|
334
346
|
model_type: Detection model type to use, e.g. "FI-1".
|
|
347
|
+
reference_img_path: Required when faceSimilarityCheck=True.
|
|
335
348
|
isSingleFace: Whether to check for a single face.
|
|
336
|
-
faceswapCheck: Whether to check for face swapping.
|
|
349
|
+
faceswapCheck: Whether to check for face swapping (video only).
|
|
337
350
|
livenessCheck: Whether to check for liveness.
|
|
338
|
-
faceSimilarityCheck: Whether to check for face similarity.
|
|
339
|
-
auto_polling: If True (default), blocks until processing completes
|
|
340
|
-
|
|
341
|
-
the
|
|
351
|
+
faceSimilarityCheck: Whether to check for face similarity (image only).
|
|
352
|
+
auto_polling: If True (default), blocks until processing completes and
|
|
353
|
+
automatically fetches the detection result from resultURL, merging
|
|
354
|
+
it into the returned dict under the key 'result'.
|
|
355
|
+
If False, returns immediately after upload with initial metadata.
|
|
342
356
|
interval: Polling interval in seconds (used only when auto_polling=True).
|
|
343
357
|
timeout: Timeout in seconds (used only when auto_polling=True).
|
|
344
358
|
|
|
345
359
|
Returns:
|
|
346
|
-
If auto_polling=True:
|
|
360
|
+
If auto_polling=True: media dict with an added 'result' key containing
|
|
361
|
+
the full detection output fetched from resultURL.
|
|
347
362
|
If auto_polling=False: the initial upload metadata dict (includes 'mid').
|
|
348
363
|
"""
|
|
364
|
+
if self._content_type(path).startswith("image/") and faceswapCheck:
|
|
365
|
+
raise ValueError("faceswapCheck cannot be True for image media")
|
|
366
|
+
if self._content_type(path).startswith("video/") and faceSimilarityCheck:
|
|
367
|
+
raise ValueError("faceSimilarityCheck cannot be True for video media")
|
|
368
|
+
if faceSimilarityCheck and not reference_img_path:
|
|
369
|
+
raise ValueError("reference_img_path must be provided if faceSimilarityCheck is True")
|
|
370
|
+
|
|
349
371
|
fi_params = {
|
|
350
372
|
"reference_img_path": reference_img_path,
|
|
351
|
-
"isSingleFace":
|
|
373
|
+
"isSingleFace": isSingleFace,
|
|
352
374
|
"faceswapCheck": faceswapCheck,
|
|
353
375
|
"livenessCheck": livenessCheck,
|
|
354
376
|
"faceSimilarityCheck": faceSimilarityCheck,
|
|
355
377
|
}
|
|
356
|
-
if self._content_type(path).startswith("image/") and faceswapCheck == True:
|
|
357
|
-
raise ValueError("faceswapCheck cannot be True for image media")
|
|
358
|
-
if self._content_type(path).startswith("video/") and faceSimilarityCheck == True:
|
|
359
|
-
raise ValueError("faceSimilarityCheck cannot be True for video media")
|
|
360
|
-
if faceSimilarityCheck == True and (not reference_img_path or reference_img_path == None):
|
|
361
|
-
raise ValueError("reference_img_path must be provided if faceSimilarityCheck is True")
|
|
362
378
|
|
|
363
379
|
meta = self.upload_file(path, model_type=model_type, **fi_params)
|
|
364
380
|
if not auto_polling:
|
|
@@ -366,14 +382,13 @@ class AuthentaClient:
|
|
|
366
382
|
mid = meta.get("mid")
|
|
367
383
|
if not mid:
|
|
368
384
|
raise RuntimeError("No 'mid' in upload response")
|
|
369
|
-
|
|
385
|
+
media = self.wait_for_media(mid, interval=interval, timeout=timeout)
|
|
386
|
+
media["result"] = self.get_result(media)
|
|
387
|
+
return media
|
|
370
388
|
|
|
371
389
|
def delete_media(self, mid: str) -> None:
|
|
372
390
|
"""DELETE /api/media/{mid}: delete a media record."""
|
|
373
391
|
url = f"{self.base_url}/api/media/{mid}"
|
|
374
|
-
|
|
375
|
-
resp = cffi_requests.delete(url, headers=self._headers(), impersonate="chrome", timeout=30)
|
|
376
|
-
else:
|
|
377
|
-
resp = requests.delete(url, headers=self._headers(), timeout=30)
|
|
392
|
+
resp = requests.delete(url, headers=self._headers(), timeout=30)
|
|
378
393
|
if not resp.ok:
|
|
379
394
|
_raise_for_authenta_error(resp)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|