diffio 0.1.0__tar.gz → 0.1.2__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.
- {diffio-0.1.0/src/diffio.egg-info → diffio-0.1.2}/PKG-INFO +35 -20
- {diffio-0.1.0 → diffio-0.1.2}/README.md +31 -19
- {diffio-0.1.0 → diffio-0.1.2}/pyproject.toml +7 -2
- {diffio-0.1.0 → diffio-0.1.2}/src/diffio/__init__.py +1 -3
- {diffio-0.1.0 → diffio-0.1.2}/src/diffio/client.py +54 -50
- {diffio-0.1.0 → diffio-0.1.2}/src/diffio/types.py +0 -15
- {diffio-0.1.0 → diffio-0.1.2/src/diffio.egg-info}/PKG-INFO +35 -20
- {diffio-0.1.0 → diffio-0.1.2}/src/diffio.egg-info/requires.txt +1 -0
- {diffio-0.1.0 → diffio-0.1.2}/tests/test_client.py +3 -32
- {diffio-0.1.0 → diffio-0.1.2}/LICENSE +0 -0
- {diffio-0.1.0 → diffio-0.1.2}/setup.cfg +0 -0
- {diffio-0.1.0 → diffio-0.1.2}/src/diffio/errors.py +0 -0
- {diffio-0.1.0 → diffio-0.1.2}/src/diffio/testing.py +0 -0
- {diffio-0.1.0 → diffio-0.1.2}/src/diffio.egg-info/SOURCES.txt +0 -0
- {diffio-0.1.0 → diffio-0.1.2}/src/diffio.egg-info/dependency_links.txt +0 -0
- {diffio-0.1.0 → diffio-0.1.2}/src/diffio.egg-info/top_level.txt +0 -0
- {diffio-0.1.0 → diffio-0.1.2}/tests/test_emulator_e2e.py +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: diffio
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python SDK for the Diffio API.
|
|
5
5
|
Author: Diffio
|
|
6
6
|
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://diffio.ai
|
|
8
|
+
Project-URL: Repository, https://github.com/Diffio-AI/diffio-python
|
|
7
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
8
10
|
Classifier: Operating System :: OS Independent
|
|
9
11
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -17,6 +19,7 @@ Requires-Python: >=3.8
|
|
|
17
19
|
Description-Content-Type: text/markdown
|
|
18
20
|
License-File: LICENSE
|
|
19
21
|
Requires-Dist: httpx>=0.24.0
|
|
22
|
+
Requires-Dist: svix<2.0.0,>=1.84.1
|
|
20
23
|
Provides-Extra: dev
|
|
21
24
|
Requires-Dist: build>=1.0; extra == "dev"
|
|
22
25
|
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
@@ -43,17 +46,11 @@ pip install -e .
|
|
|
43
46
|
|
|
44
47
|
## Configuration
|
|
45
48
|
|
|
46
|
-
Set the API key with `DIFFIO_API_KEY`.
|
|
49
|
+
Set the API key with `DIFFIO_API_KEY`. If you need to set the base URL explicitly, use the production endpoint with `DIFFIO_API_BASE_URL`.
|
|
47
50
|
|
|
48
51
|
```bash
|
|
49
52
|
export DIFFIO_API_KEY="diffio_live_..."
|
|
50
|
-
export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net"
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
For emulators, set the base URL to the Functions emulator host.
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
export DIFFIO_API_BASE_URL="http://127.0.0.1:5001/diffioai/us-central1"
|
|
53
|
+
export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net/v1"
|
|
57
54
|
```
|
|
58
55
|
|
|
59
56
|
## Request options
|
|
@@ -192,16 +189,6 @@ for generation in generations.generations:
|
|
|
192
189
|
print(generation.generationId, generation.status)
|
|
193
190
|
```
|
|
194
191
|
|
|
195
|
-
## Webhooks portal access
|
|
196
|
-
|
|
197
|
-
```py
|
|
198
|
-
from diffio import DiffioClient
|
|
199
|
-
|
|
200
|
-
client = DiffioClient(apiKey="diffio_live_...")
|
|
201
|
-
portal = client.webhooks.get_portal_access(mode="test")
|
|
202
|
-
print(portal.portalUrl)
|
|
203
|
-
```
|
|
204
|
-
|
|
205
192
|
## Send a test webhook event
|
|
206
193
|
|
|
207
194
|
```py
|
|
@@ -210,13 +197,41 @@ from diffio import DiffioClient
|
|
|
210
197
|
client = DiffioClient(apiKey="diffio_live_...")
|
|
211
198
|
event = client.webhooks.send_test_event(
|
|
212
199
|
eventType="generation.completed",
|
|
213
|
-
mode="
|
|
200
|
+
mode="live",
|
|
214
201
|
samplePayload={"apiProjectId": "proj_123"},
|
|
215
202
|
)
|
|
216
203
|
|
|
217
204
|
print(event.svixMessageId)
|
|
218
205
|
```
|
|
219
206
|
|
|
207
|
+
## Verify webhook signatures
|
|
208
|
+
|
|
209
|
+
Use the raw request body (bytes) plus the `svix-*` headers and your webhook signing secret.
|
|
210
|
+
|
|
211
|
+
```py
|
|
212
|
+
from fastapi import FastAPI, Request, HTTPException
|
|
213
|
+
from diffio import DiffioClient
|
|
214
|
+
import os
|
|
215
|
+
|
|
216
|
+
app = FastAPI()
|
|
217
|
+
client = DiffioClient(apiKey=os.environ["DIFFIO_API_KEY"])
|
|
218
|
+
|
|
219
|
+
@app.post("/webhooks/diffio")
|
|
220
|
+
async def diffio_webhook(request: Request):
|
|
221
|
+
payload = await request.body()
|
|
222
|
+
headers = request.headers
|
|
223
|
+
try:
|
|
224
|
+
event = client.webhooks.verify_signature(
|
|
225
|
+
payload=payload,
|
|
226
|
+
headers=headers,
|
|
227
|
+
secret=os.environ["DIFFIO_WEBHOOK_SECRET"],
|
|
228
|
+
)
|
|
229
|
+
except Exception:
|
|
230
|
+
raise HTTPException(status_code=400, detail="Invalid signature")
|
|
231
|
+
print("Webhook received", event.eventType)
|
|
232
|
+
return {"ok": True}
|
|
233
|
+
```
|
|
234
|
+
|
|
220
235
|
## Tutorials
|
|
221
236
|
|
|
222
237
|
* Audio restoration CLI tutorial: `tutorials/audio-restoration-cli/README.md`
|
|
@@ -18,17 +18,11 @@ pip install -e .
|
|
|
18
18
|
|
|
19
19
|
## Configuration
|
|
20
20
|
|
|
21
|
-
Set the API key with `DIFFIO_API_KEY`.
|
|
21
|
+
Set the API key with `DIFFIO_API_KEY`. If you need to set the base URL explicitly, use the production endpoint with `DIFFIO_API_BASE_URL`.
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
export DIFFIO_API_KEY="diffio_live_..."
|
|
25
|
-
export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net"
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
For emulators, set the base URL to the Functions emulator host.
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
export DIFFIO_API_BASE_URL="http://127.0.0.1:5001/diffioai/us-central1"
|
|
25
|
+
export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net/v1"
|
|
32
26
|
```
|
|
33
27
|
|
|
34
28
|
## Request options
|
|
@@ -167,16 +161,6 @@ for generation in generations.generations:
|
|
|
167
161
|
print(generation.generationId, generation.status)
|
|
168
162
|
```
|
|
169
163
|
|
|
170
|
-
## Webhooks portal access
|
|
171
|
-
|
|
172
|
-
```py
|
|
173
|
-
from diffio import DiffioClient
|
|
174
|
-
|
|
175
|
-
client = DiffioClient(apiKey="diffio_live_...")
|
|
176
|
-
portal = client.webhooks.get_portal_access(mode="test")
|
|
177
|
-
print(portal.portalUrl)
|
|
178
|
-
```
|
|
179
|
-
|
|
180
164
|
## Send a test webhook event
|
|
181
165
|
|
|
182
166
|
```py
|
|
@@ -185,13 +169,41 @@ from diffio import DiffioClient
|
|
|
185
169
|
client = DiffioClient(apiKey="diffio_live_...")
|
|
186
170
|
event = client.webhooks.send_test_event(
|
|
187
171
|
eventType="generation.completed",
|
|
188
|
-
mode="
|
|
172
|
+
mode="live",
|
|
189
173
|
samplePayload={"apiProjectId": "proj_123"},
|
|
190
174
|
)
|
|
191
175
|
|
|
192
176
|
print(event.svixMessageId)
|
|
193
177
|
```
|
|
194
178
|
|
|
179
|
+
## Verify webhook signatures
|
|
180
|
+
|
|
181
|
+
Use the raw request body (bytes) plus the `svix-*` headers and your webhook signing secret.
|
|
182
|
+
|
|
183
|
+
```py
|
|
184
|
+
from fastapi import FastAPI, Request, HTTPException
|
|
185
|
+
from diffio import DiffioClient
|
|
186
|
+
import os
|
|
187
|
+
|
|
188
|
+
app = FastAPI()
|
|
189
|
+
client = DiffioClient(apiKey=os.environ["DIFFIO_API_KEY"])
|
|
190
|
+
|
|
191
|
+
@app.post("/webhooks/diffio")
|
|
192
|
+
async def diffio_webhook(request: Request):
|
|
193
|
+
payload = await request.body()
|
|
194
|
+
headers = request.headers
|
|
195
|
+
try:
|
|
196
|
+
event = client.webhooks.verify_signature(
|
|
197
|
+
payload=payload,
|
|
198
|
+
headers=headers,
|
|
199
|
+
secret=os.environ["DIFFIO_WEBHOOK_SECRET"],
|
|
200
|
+
)
|
|
201
|
+
except Exception:
|
|
202
|
+
raise HTTPException(status_code=400, detail="Invalid signature")
|
|
203
|
+
print("Webhook received", event.eventType)
|
|
204
|
+
return {"ok": True}
|
|
205
|
+
```
|
|
206
|
+
|
|
195
207
|
## Tutorials
|
|
196
208
|
|
|
197
209
|
* Audio restoration CLI tutorial: `tutorials/audio-restoration-cli/README.md`
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "diffio"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "Python SDK for the Diffio API."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -13,7 +13,8 @@ authors = [
|
|
|
13
13
|
{ name = "Diffio" }
|
|
14
14
|
]
|
|
15
15
|
dependencies = [
|
|
16
|
-
"httpx>=0.24.0"
|
|
16
|
+
"httpx>=0.24.0",
|
|
17
|
+
"svix>=1.84.1,<2.0.0"
|
|
17
18
|
]
|
|
18
19
|
classifiers = [
|
|
19
20
|
"License :: OSI Approved :: MIT License",
|
|
@@ -34,6 +35,10 @@ dev = [
|
|
|
34
35
|
"twine>=5.0",
|
|
35
36
|
]
|
|
36
37
|
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://diffio.ai"
|
|
40
|
+
Repository = "https://github.com/Diffio-AI/diffio-python"
|
|
41
|
+
|
|
37
42
|
[tool.setuptools]
|
|
38
43
|
package-dir = { "" = "src" }
|
|
39
44
|
|
|
@@ -24,7 +24,6 @@ from .types import (
|
|
|
24
24
|
ProjectSummary,
|
|
25
25
|
WebhookEventType,
|
|
26
26
|
WebhookMode,
|
|
27
|
-
WebhookPortalResponse,
|
|
28
27
|
WebhookTestEventResponse,
|
|
29
28
|
)
|
|
30
29
|
|
|
@@ -51,9 +50,8 @@ __all__ = [
|
|
|
51
50
|
"RequestOptions",
|
|
52
51
|
"WebhookEventType",
|
|
53
52
|
"WebhookMode",
|
|
54
|
-
"WebhookPortalResponse",
|
|
55
53
|
"WebhookTestEventResponse",
|
|
56
54
|
"WebhooksClient",
|
|
57
55
|
]
|
|
58
56
|
|
|
59
|
-
__version__ = "0.1.
|
|
57
|
+
__version__ = "0.1.2"
|
|
@@ -7,6 +7,7 @@ import warnings
|
|
|
7
7
|
from urllib.parse import urlparse
|
|
8
8
|
|
|
9
9
|
import httpx
|
|
10
|
+
from svix.webhooks import Webhook
|
|
10
11
|
|
|
11
12
|
from .errors import DiffioApiError
|
|
12
13
|
from .types import (
|
|
@@ -16,12 +17,12 @@ from .types import (
|
|
|
16
17
|
DownloadType,
|
|
17
18
|
GenerationDownloadResponse,
|
|
18
19
|
GenerationProgressResponse,
|
|
20
|
+
GenerationWebhookEvent,
|
|
19
21
|
ListProjectGenerationsResponse,
|
|
20
22
|
ListProjectsResponse,
|
|
21
23
|
ModelKey,
|
|
22
24
|
WebhookEventType,
|
|
23
25
|
WebhookMode,
|
|
24
|
-
WebhookPortalResponse,
|
|
25
26
|
WebhookTestEventResponse,
|
|
26
27
|
)
|
|
27
28
|
|
|
@@ -100,6 +101,35 @@ def _merge_request_options(base_options, override_options):
|
|
|
100
101
|
)
|
|
101
102
|
|
|
102
103
|
|
|
104
|
+
def _normalize_svix_headers(headers):
|
|
105
|
+
normalized = {}
|
|
106
|
+
if headers is None:
|
|
107
|
+
return normalized
|
|
108
|
+
if not hasattr(headers, "items"):
|
|
109
|
+
raise ValueError("headers must be a dict-like object")
|
|
110
|
+
for key, value in headers.items():
|
|
111
|
+
if value is None:
|
|
112
|
+
continue
|
|
113
|
+
if isinstance(value, (list, tuple)):
|
|
114
|
+
normalized[str(key).lower()] = ",".join([str(item) for item in value])
|
|
115
|
+
else:
|
|
116
|
+
normalized[str(key).lower()] = str(value)
|
|
117
|
+
return normalized
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _extract_svix_headers(headers):
|
|
121
|
+
normalized = _normalize_svix_headers(headers)
|
|
122
|
+
required = ["svix-id", "svix-timestamp", "svix-signature"]
|
|
123
|
+
missing = [header for header in required if not normalized.get(header)]
|
|
124
|
+
if missing:
|
|
125
|
+
raise DiffioApiError(f"Missing webhook headers: {', '.join(missing)}")
|
|
126
|
+
return {
|
|
127
|
+
"svix-id": normalized["svix-id"],
|
|
128
|
+
"svix-timestamp": normalized["svix-timestamp"],
|
|
129
|
+
"svix-signature": normalized["svix-signature"],
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
103
133
|
def _default_request_options():
|
|
104
134
|
return RequestOptions(
|
|
105
135
|
headers={},
|
|
@@ -496,42 +526,6 @@ class DiffioClient:
|
|
|
496
526
|
)
|
|
497
527
|
return GenerationDownloadResponse.from_dict(response)
|
|
498
528
|
|
|
499
|
-
def get_webhooks_portal_access(
|
|
500
|
-
self,
|
|
501
|
-
*,
|
|
502
|
-
mode,
|
|
503
|
-
apiKeyId=None,
|
|
504
|
-
requestOptions=None,
|
|
505
|
-
):
|
|
506
|
-
"""
|
|
507
|
-
Gets the Svix App Portal URL for configuring webhooks.
|
|
508
|
-
|
|
509
|
-
Parameters
|
|
510
|
-
----------
|
|
511
|
-
mode : str
|
|
512
|
-
Webhook mode, test or live.
|
|
513
|
-
apiKeyId : str, optional
|
|
514
|
-
Optional API key id to validate access.
|
|
515
|
-
|
|
516
|
-
Returns
|
|
517
|
-
-------
|
|
518
|
-
WebhookPortalResponse
|
|
519
|
-
App portal URL and mode.
|
|
520
|
-
"""
|
|
521
|
-
if mode not in WebhookMode:
|
|
522
|
-
raise ValueError("mode must be test or live")
|
|
523
|
-
payload = {"mode": mode}
|
|
524
|
-
if apiKeyId is not None:
|
|
525
|
-
payload["apiKeyId"] = apiKeyId
|
|
526
|
-
|
|
527
|
-
response = self._request(
|
|
528
|
-
"POST",
|
|
529
|
-
"webhooks/app_portal_access",
|
|
530
|
-
json_payload=payload,
|
|
531
|
-
requestOptions=requestOptions,
|
|
532
|
-
)
|
|
533
|
-
return WebhookPortalResponse.from_dict(response)
|
|
534
|
-
|
|
535
529
|
def send_webhook_test_event(
|
|
536
530
|
self,
|
|
537
531
|
*,
|
|
@@ -841,19 +835,6 @@ class WebhooksClient:
|
|
|
841
835
|
def __init__(self, parent):
|
|
842
836
|
self._parent = parent
|
|
843
837
|
|
|
844
|
-
def get_portal_access(
|
|
845
|
-
self,
|
|
846
|
-
*,
|
|
847
|
-
mode,
|
|
848
|
-
apiKeyId=None,
|
|
849
|
-
requestOptions=None,
|
|
850
|
-
):
|
|
851
|
-
return self._parent.get_webhooks_portal_access(
|
|
852
|
-
mode=mode,
|
|
853
|
-
apiKeyId=apiKeyId,
|
|
854
|
-
requestOptions=requestOptions,
|
|
855
|
-
)
|
|
856
|
-
|
|
857
838
|
def send_test_event(
|
|
858
839
|
self,
|
|
859
840
|
*,
|
|
@@ -871,6 +852,29 @@ class WebhooksClient:
|
|
|
871
852
|
requestOptions=requestOptions,
|
|
872
853
|
)
|
|
873
854
|
|
|
855
|
+
def verify_signature(
|
|
856
|
+
self,
|
|
857
|
+
*,
|
|
858
|
+
payload,
|
|
859
|
+
headers,
|
|
860
|
+
secret,
|
|
861
|
+
):
|
|
862
|
+
if not secret:
|
|
863
|
+
raise DiffioApiError("secret is required")
|
|
864
|
+
if payload is None:
|
|
865
|
+
raise DiffioApiError("payload is required")
|
|
866
|
+
if not isinstance(payload, (bytes, str)):
|
|
867
|
+
raise DiffioApiError("payload must be bytes or str")
|
|
868
|
+
|
|
869
|
+
webhook = Webhook(secret)
|
|
870
|
+
try:
|
|
871
|
+
event = webhook.verify(payload, _extract_svix_headers(headers))
|
|
872
|
+
except Exception as exc:
|
|
873
|
+
raise DiffioApiError(str(exc))
|
|
874
|
+
if not isinstance(event, dict):
|
|
875
|
+
raise DiffioApiError("Webhook payload must be an object")
|
|
876
|
+
return GenerationWebhookEvent.from_dict(event)
|
|
877
|
+
|
|
874
878
|
|
|
875
879
|
class AudioIsolationClient:
|
|
876
880
|
def __init__(self, parent):
|
|
@@ -237,21 +237,6 @@ class GenerationDownloadResponse:
|
|
|
237
237
|
)
|
|
238
238
|
|
|
239
239
|
|
|
240
|
-
class WebhookPortalResponse:
|
|
241
|
-
def __init__(self, portalUrl, mode, apiKeyId=None):
|
|
242
|
-
self.portalUrl = portalUrl
|
|
243
|
-
self.mode = mode
|
|
244
|
-
self.apiKeyId = apiKeyId
|
|
245
|
-
|
|
246
|
-
@classmethod
|
|
247
|
-
def from_dict(cls, data):
|
|
248
|
-
return cls(
|
|
249
|
-
portalUrl=data["portalUrl"],
|
|
250
|
-
mode=data.get("mode"),
|
|
251
|
-
apiKeyId=data.get("apiKeyId"),
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
|
|
255
240
|
class WebhookTestEventResponse:
|
|
256
241
|
def __init__(self, svixMessageId, eventId, eventType, mode, apiKeyId=None):
|
|
257
242
|
self.svixMessageId = svixMessageId
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: diffio
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python SDK for the Diffio API.
|
|
5
5
|
Author: Diffio
|
|
6
6
|
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://diffio.ai
|
|
8
|
+
Project-URL: Repository, https://github.com/Diffio-AI/diffio-python
|
|
7
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
8
10
|
Classifier: Operating System :: OS Independent
|
|
9
11
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -17,6 +19,7 @@ Requires-Python: >=3.8
|
|
|
17
19
|
Description-Content-Type: text/markdown
|
|
18
20
|
License-File: LICENSE
|
|
19
21
|
Requires-Dist: httpx>=0.24.0
|
|
22
|
+
Requires-Dist: svix<2.0.0,>=1.84.1
|
|
20
23
|
Provides-Extra: dev
|
|
21
24
|
Requires-Dist: build>=1.0; extra == "dev"
|
|
22
25
|
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
@@ -43,17 +46,11 @@ pip install -e .
|
|
|
43
46
|
|
|
44
47
|
## Configuration
|
|
45
48
|
|
|
46
|
-
Set the API key with `DIFFIO_API_KEY`.
|
|
49
|
+
Set the API key with `DIFFIO_API_KEY`. If you need to set the base URL explicitly, use the production endpoint with `DIFFIO_API_BASE_URL`.
|
|
47
50
|
|
|
48
51
|
```bash
|
|
49
52
|
export DIFFIO_API_KEY="diffio_live_..."
|
|
50
|
-
export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net"
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
For emulators, set the base URL to the Functions emulator host.
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
export DIFFIO_API_BASE_URL="http://127.0.0.1:5001/diffioai/us-central1"
|
|
53
|
+
export DIFFIO_API_BASE_URL="https://us-central1-diffioai.cloudfunctions.net/v1"
|
|
57
54
|
```
|
|
58
55
|
|
|
59
56
|
## Request options
|
|
@@ -192,16 +189,6 @@ for generation in generations.generations:
|
|
|
192
189
|
print(generation.generationId, generation.status)
|
|
193
190
|
```
|
|
194
191
|
|
|
195
|
-
## Webhooks portal access
|
|
196
|
-
|
|
197
|
-
```py
|
|
198
|
-
from diffio import DiffioClient
|
|
199
|
-
|
|
200
|
-
client = DiffioClient(apiKey="diffio_live_...")
|
|
201
|
-
portal = client.webhooks.get_portal_access(mode="test")
|
|
202
|
-
print(portal.portalUrl)
|
|
203
|
-
```
|
|
204
|
-
|
|
205
192
|
## Send a test webhook event
|
|
206
193
|
|
|
207
194
|
```py
|
|
@@ -210,13 +197,41 @@ from diffio import DiffioClient
|
|
|
210
197
|
client = DiffioClient(apiKey="diffio_live_...")
|
|
211
198
|
event = client.webhooks.send_test_event(
|
|
212
199
|
eventType="generation.completed",
|
|
213
|
-
mode="
|
|
200
|
+
mode="live",
|
|
214
201
|
samplePayload={"apiProjectId": "proj_123"},
|
|
215
202
|
)
|
|
216
203
|
|
|
217
204
|
print(event.svixMessageId)
|
|
218
205
|
```
|
|
219
206
|
|
|
207
|
+
## Verify webhook signatures
|
|
208
|
+
|
|
209
|
+
Use the raw request body (bytes) plus the `svix-*` headers and your webhook signing secret.
|
|
210
|
+
|
|
211
|
+
```py
|
|
212
|
+
from fastapi import FastAPI, Request, HTTPException
|
|
213
|
+
from diffio import DiffioClient
|
|
214
|
+
import os
|
|
215
|
+
|
|
216
|
+
app = FastAPI()
|
|
217
|
+
client = DiffioClient(apiKey=os.environ["DIFFIO_API_KEY"])
|
|
218
|
+
|
|
219
|
+
@app.post("/webhooks/diffio")
|
|
220
|
+
async def diffio_webhook(request: Request):
|
|
221
|
+
payload = await request.body()
|
|
222
|
+
headers = request.headers
|
|
223
|
+
try:
|
|
224
|
+
event = client.webhooks.verify_signature(
|
|
225
|
+
payload=payload,
|
|
226
|
+
headers=headers,
|
|
227
|
+
secret=os.environ["DIFFIO_WEBHOOK_SECRET"],
|
|
228
|
+
)
|
|
229
|
+
except Exception:
|
|
230
|
+
raise HTTPException(status_code=400, detail="Invalid signature")
|
|
231
|
+
print("Webhook received", event.eventType)
|
|
232
|
+
return {"ok": True}
|
|
233
|
+
```
|
|
234
|
+
|
|
220
235
|
## Tutorials
|
|
221
236
|
|
|
222
237
|
* Audio restoration CLI tutorial: `tutorials/audio-restoration-cli/README.md`
|
|
@@ -660,35 +660,6 @@ def test_list_project_generations_payload_and_response():
|
|
|
660
660
|
assert response.generations[0].progress is None
|
|
661
661
|
|
|
662
662
|
|
|
663
|
-
def test_webhooks_portal_access_payload_and_response():
|
|
664
|
-
received = {}
|
|
665
|
-
|
|
666
|
-
def handler(request: httpx.Request) -> httpx.Response:
|
|
667
|
-
received["path"] = request.url.path
|
|
668
|
-
payload = json.loads(request.content.decode("utf-8"))
|
|
669
|
-
received["payload"] = payload
|
|
670
|
-
return httpx.Response(
|
|
671
|
-
200,
|
|
672
|
-
json={
|
|
673
|
-
"portalUrl": "https://app.svix.com/app-portal/test",
|
|
674
|
-
"mode": "test",
|
|
675
|
-
"apiKeyId": "key_123",
|
|
676
|
-
},
|
|
677
|
-
)
|
|
678
|
-
|
|
679
|
-
transport = httpx.MockTransport(handler)
|
|
680
|
-
http_client = httpx.Client(base_url="https://api.test", transport=transport)
|
|
681
|
-
client = DiffioClient(apiKey="diffio_live_test", baseUrl="https://api.test", httpClient=http_client)
|
|
682
|
-
|
|
683
|
-
response = client.webhooks.get_portal_access(mode="test", apiKeyId="key_123")
|
|
684
|
-
|
|
685
|
-
assert received["path"] == "/v1/webhooks/app_portal_access"
|
|
686
|
-
assert received["payload"]["mode"] == "test"
|
|
687
|
-
assert received["payload"]["apiKeyId"] == "key_123"
|
|
688
|
-
assert response.portalUrl == "https://app.svix.com/app-portal/test"
|
|
689
|
-
assert response.mode == "test"
|
|
690
|
-
|
|
691
|
-
|
|
692
663
|
def test_webhooks_send_test_event_payload_and_response():
|
|
693
664
|
received = {}
|
|
694
665
|
|
|
@@ -702,7 +673,7 @@ def test_webhooks_send_test_event_payload_and_response():
|
|
|
702
673
|
"svixMessageId": "msg_123",
|
|
703
674
|
"eventId": "evt_123",
|
|
704
675
|
"eventType": "generation.completed",
|
|
705
|
-
"mode": "
|
|
676
|
+
"mode": "live",
|
|
706
677
|
"apiKeyId": "key_123",
|
|
707
678
|
},
|
|
708
679
|
)
|
|
@@ -713,14 +684,14 @@ def test_webhooks_send_test_event_payload_and_response():
|
|
|
713
684
|
|
|
714
685
|
response = client.webhooks.send_test_event(
|
|
715
686
|
eventType="generation.completed",
|
|
716
|
-
mode="
|
|
687
|
+
mode="live",
|
|
717
688
|
apiKeyId="key_123",
|
|
718
689
|
samplePayload={"apiProjectId": "proj_123"},
|
|
719
690
|
)
|
|
720
691
|
|
|
721
692
|
assert received["path"] == "/v1/webhooks/send_test_event"
|
|
722
693
|
assert received["payload"]["eventType"] == "generation.completed"
|
|
723
|
-
assert received["payload"]["mode"] == "
|
|
694
|
+
assert received["payload"]["mode"] == "live"
|
|
724
695
|
assert received["payload"]["apiKeyId"] == "key_123"
|
|
725
696
|
assert received["payload"]["samplePayload"]["apiProjectId"] == "proj_123"
|
|
726
697
|
assert response.svixMessageId == "msg_123"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|