Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
parkpow
GitHub Repository: parkpow/deep-license-plate-recognition
Path: blob/master/webhooks/webhook_tester/webhook_tester.py
1085 views
1
import argparse
2
import json
3
import os
4
from datetime import datetime, timezone
5
from io import BytesIO
6
from typing import Any
7
8
import requests
9
10
11
class WebhookError(Exception):
12
"""Raised when a webhook response does not return 200 status."""
13
14
15
class WebhookTester:
16
"""Main class to use in testing the webhook."""
17
18
def __init__(
19
self,
20
url: str,
21
token: str | None = None,
22
camera_id: str | None = None,
23
plate: str | None = None,
24
region_code: str | None = None,
25
timestamp: str | None = None,
26
):
27
self.url = url or os.environ.get("URL", "")
28
if not self.url:
29
raise ValueError("Set URL environment variable when running docker.")
30
self.token = token or os.environ.get("TOKEN")
31
self.camera_id = camera_id or os.environ.get("CAMERA", "camera-1")
32
self.plate = plate or os.environ.get("PLATE", "pl8rec")
33
self.region_code = region_code or os.environ.get("REGION", "us-ca")
34
self.timestamp = timestamp or os.environ.get(
35
"TIMESTAMP", datetime.now(timezone.utc).isoformat()
36
)
37
38
def get_webhook_payload(self) -> dict[str, Any]:
39
"""Return a sample payload to the request."""
40
return {
41
"json": json.dumps(
42
{
43
"hook": {
44
"target": self.url,
45
"id": self.camera_id,
46
"event": "recognition",
47
"filename": (f"{self.camera_id}_screenshots/image.jpg"),
48
},
49
"data": {
50
"camera_id": self.camera_id,
51
"filename": (f"{self.camera_id}_screenshots/image.jpg"),
52
"timestamp": self.timestamp,
53
"timestamp_local": self.timestamp,
54
"results": [
55
{
56
"box": {
57
"xmax": 412,
58
"xmin": 337,
59
"ymax": 305,
60
"ymin": 270,
61
},
62
"candidates": [
63
{"plate": self.plate, "score": 0.902},
64
{"plate": "plbrec", "score": 0.758},
65
],
66
"color": [
67
{"color": "red", "score": 0.699},
68
{"color": "black", "score": 0.134},
69
{"color": "blue", "score": 0.03},
70
],
71
"dscore": 0.757,
72
"model_make": [
73
{"make": "Porsche", "model": "911", "score": 0.43},
74
{
75
"make": "Porsche",
76
"model": "Carrera",
77
"score": 0.2,
78
},
79
{
80
"make": "Porsche",
81
"model": "Carrera GTS",
82
"score": 0.07,
83
},
84
],
85
"orientation": [
86
{"orientation": "Rear", "score": 0.883},
87
{"orientation": "Front", "score": 0.07},
88
{"orientation": "Unknown", "score": 0.047},
89
],
90
"plate": self.plate,
91
"region": {"code": self.region_code, "score": 0.179},
92
"score": 0.902,
93
"vehicle": {
94
"box": {
95
"xmax": 590,
96
"xmin": 155,
97
"ymax": 373,
98
"ymin": 71,
99
},
100
"score": 0.709,
101
"type": "Sedan",
102
},
103
"direction": 210,
104
"source_url": ("/user-data/video.mp4"),
105
"position_sec": 23.47,
106
}
107
],
108
},
109
}
110
) # end of json.dumps
111
}
112
113
def get_files_payload(self) -> dict[str, Any]:
114
"""Return a request payload containing files."""
115
url = (
116
"https://platerecognizer.com/wp-content/uploads/2020/07/"
117
"ALPR-license-plate-reader-images-API.jpg"
118
)
119
response = self.send_request("get", url)
120
print(f"This request includes a {len(response.content) / 1024:.1f} KB image.")
121
return {"upload": ("image.jpg", BytesIO(response.content))}
122
123
def send_request(
124
self,
125
method: str,
126
url: str,
127
data: dict[str, Any] | None = None,
128
files: dict[str, Any] | None = None,
129
) -> requests.Response:
130
"""
131
Send the actual request to the given URL along with the parameters.
132
133
Args:
134
url (str): The target URL.
135
data (Union[Dict[str, Any], None]): Payload to send to the URL.
136
files (Union[Dict[str, Any], None]): Files to send to the URL.
137
138
Returns:
139
requests.Response: The Response object.
140
"""
141
if method.lower() not in ["get", "post"]:
142
raise ValueError("Method not supported. Only accepts `get` or `post`.")
143
headers = {}
144
if self.token:
145
headers["Authorization"] = f"Token {self.token}"
146
try:
147
response = getattr(requests, method.lower())(
148
url, data=data, files=files, timeout=30, headers=headers
149
)
150
except requests.exceptions.Timeout as exc:
151
raise WebhookError("The request timed out.") from exc
152
except requests.exceptions.TooManyRedirects as exc:
153
raise WebhookError(
154
"The given URL might be misconfigured. Try a different one."
155
) from exc
156
except requests.exceptions.RequestException as request_exception:
157
raise WebhookError(str(request_exception)) from request_exception
158
159
return response
160
161
def execute(self) -> None:
162
"""Used to test the webhook."""
163
print(f"{' Sending Webhook (JSON + Image) ':-^80s}")
164
165
payload = self.get_webhook_payload()
166
files = self.get_files_payload()
167
response = self.send_request("post", self.url, payload, files)
168
content = response.text
169
if response.status_code >= 300:
170
print(f"--> Invalid status code: {response.status_code}")
171
raise WebhookError(content)
172
else:
173
print(f"Status code: {response.status_code}")
174
print(f"Response content: {content}")
175
print("--> The server successfully received the webhook.")
176
177
@staticmethod
178
def parse_args():
179
"""Parse command line arguments."""
180
parser = argparse.ArgumentParser(
181
description="Test webhook with license plate recognition data"
182
)
183
parser.add_argument("--url", help="Webhook URL to test")
184
parser.add_argument("--token", help="Header authorization token")
185
parser.add_argument("--camera-id", help="Camera ID (default: camera-1)")
186
parser.add_argument("--plate", help="License plate text (default: pl8rec)")
187
parser.add_argument("--region", help="Region code (default: us-ca)")
188
parser.add_argument(
189
"--timestamp",
190
help="Timestamp (default: current UTC time). Format: 2025-08-11T16:42:58.740143Z",
191
)
192
return parser.parse_args()
193
194
195
if __name__ == "__main__":
196
args = WebhookTester.parse_args()
197
try:
198
tester = WebhookTester(
199
url=args.url,
200
token=args.token,
201
camera_id=args.camera_id,
202
plate=args.plate,
203
region_code=args.region,
204
timestamp=args.timestamp,
205
)
206
tester.execute()
207
except KeyboardInterrupt:
208
print("Stopping...")
209
except Exception as e:
210
print("--> An error occurred:")
211
print(e)
212
print("--> The webhook failed.")
213
214