Skip to content

Commit 519f76a

Browse files
authored
Merge pull request #22 from Zipstack/add-webhook-managment-fns
Added webhook management functions
2 parents c7237ce + 8a429f8 commit 519f76a

File tree

4 files changed

+132
-8
lines changed

4 files changed

+132
-8
lines changed

src/unstract/llmwhisperer/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "2.2.1"
1+
__version__ = "2.3.0"
22

33
from .client import LLMWhispererClient # noqa: F401
44
from .client_v2 import LLMWhispererClientV2 # noqa: F401

src/unstract/llmwhisperer/client_v2.py

+69-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
LLMWhispererClientException: Exception raised for errors in the LLMWhispererClient.
1919
"""
2020

21-
import copy
2221
import json
2322
import logging
2423
import os
@@ -504,9 +503,44 @@ def register_webhook(self, url: str, auth_token: str, webhook_name: str) -> dict
504503
"webhook_name": webhook_name,
505504
}
506505
url = f"{self.base_url}/whisper-manage-callback"
507-
headersx = copy.deepcopy(self.headers)
508-
headersx["Content-Type"] = "application/json"
509-
req = requests.Request("POST", url, headers=headersx, json=data)
506+
req = requests.Request("POST", url, headers=self.headers, json=data)
507+
prepared = req.prepare()
508+
s = requests.Session()
509+
response = s.send(prepared, timeout=self.api_timeout)
510+
if response.status_code != 201:
511+
err = json.loads(response.text)
512+
err["status_code"] = response.status_code
513+
raise LLMWhispererClientException(err)
514+
return json.loads(response.text)
515+
516+
def update_webhook_details(self, webhook_name: str, url: str, auth_token: str) -> dict:
517+
"""Updates the details of a webhook from the LLMWhisperer API.
518+
519+
This method sends a PUT request to the '/whisper-manage-callback' endpoint of the LLMWhisperer API.
520+
The response is a JSON object containing the status of the webhook update.
521+
522+
Refer to https://docs.unstract.com/llm_whisperer/apis/
523+
524+
Args:
525+
webhook_name (str): The name of the webhook.
526+
url (str): The URL of the webhook.
527+
auth_token (str): The authentication token for the webhook.
528+
529+
Returns:
530+
dict: A dictionary containing the status code and the response from the API.
531+
532+
Raises:
533+
LLMWhispererClientException: If the API request fails, it raises an exception with
534+
the error message and status code returned by the API.
535+
"""
536+
537+
data = {
538+
"url": url,
539+
"auth_token": auth_token,
540+
"webhook_name": webhook_name,
541+
}
542+
url = f"{self.base_url}/whisper-manage-callback"
543+
req = requests.Request("PUT", url, headers=self.headers, json=data)
510544
prepared = req.prepare()
511545
s = requests.Session()
512546
response = s.send(prepared, timeout=self.api_timeout)
@@ -547,6 +581,37 @@ def get_webhook_details(self, webhook_name: str) -> dict:
547581
raise LLMWhispererClientException(err)
548582
return json.loads(response.text)
549583

584+
def delete_webhook(self, webhook_name: str) -> dict:
585+
"""Deletes a webhook from the LLMWhisperer API.
586+
587+
This method sends a DELETE request to the '/whisper-manage-callback' endpoint of the LLMWhisperer API.
588+
The response is a JSON object containing the status of the webhook deletion.
589+
590+
Refer to https://docs.unstract.com/llm_whisperer/apis/
591+
592+
Args:
593+
webhook_name (str): The name of the webhook.
594+
595+
Returns:
596+
dict: A dictionary containing the status code and the response from the API.
597+
598+
Raises:
599+
LLMWhispererClientException: If the API request fails, it raises an exception with
600+
the error message and status code returned by the API.
601+
"""
602+
603+
url = f"{self.base_url}/whisper-manage-callback"
604+
params = {"webhook_name": webhook_name}
605+
req = requests.Request("DELETE", url, headers=self.headers, params=params)
606+
prepared = req.prepare()
607+
s = requests.Session()
608+
response = s.send(prepared, timeout=self.api_timeout)
609+
if response.status_code != 200:
610+
err = json.loads(response.text)
611+
err["status_code"] = response.status_code
612+
raise LLMWhispererClientException(err)
613+
return json.loads(response.text)
614+
550615
def get_highlight_rect(
551616
self,
552617
line_metadata: list[int],

tests/integration/client_v2_test.py

+59
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import pytest
77

8+
from unstract.llmwhisperer.client_v2 import LLMWhispererClientException
9+
810
logger = logging.getLogger(__name__)
911

1012

@@ -168,6 +170,63 @@ def test_whisper_v2_url_in_post(client_v2, data_dir, output_mode, mode, url, inp
168170
verify_usage(usage_before, usage_after, page_count, mode)
169171

170172

173+
@pytest.mark.parametrize(
174+
"url,token,webhook_name",
175+
[
176+
(
177+
"https://webhook.site/b76ecc5f-8320-4410-b24f-66525d2c92cb",
178+
"",
179+
"client_v2_test",
180+
),
181+
],
182+
)
183+
def test_webhook(client_v2, url, token, webhook_name):
184+
"""Tests the registration, retrieval, update, and deletion of a webhook.
185+
186+
This test method performs the following steps:
187+
1. Registers a new webhook with the provided URL, token, and webhook name.
188+
2. Retrieves the details of the registered webhook and verifies the URL, token, and webhook name.
189+
3. Updates the webhook details with a new token.
190+
4. Deletes the webhook and verifies the deletion.
191+
192+
Args:
193+
client_v2 (LLMWhispererClientV2): The client instance for making API requests.
194+
url (str): The URL of the webhook.
195+
token (str): The authentication token for the webhook.
196+
webhook_name (str): The name of the webhook.
197+
198+
Returns:
199+
None
200+
"""
201+
result = client_v2.register_webhook(url, token, webhook_name)
202+
assert isinstance(result, dict)
203+
assert result["message"] == "Webhook created successfully"
204+
205+
result = client_v2.get_webhook_details(webhook_name)
206+
assert isinstance(result, dict)
207+
assert result["url"] == url
208+
assert result["auth_token"] == token
209+
assert result["webhook_name"] == webhook_name
210+
211+
result = client_v2.update_webhook_details(webhook_name, url, "new_token")
212+
assert isinstance(result, dict)
213+
assert result["message"] == "Webhook updated successfully"
214+
215+
result = client_v2.get_webhook_details(webhook_name)
216+
assert isinstance(result, dict)
217+
assert result["auth_token"] == "new_token"
218+
219+
result = client_v2.delete_webhook(webhook_name)
220+
assert isinstance(result, dict)
221+
assert result["message"] == "Webhook deleted successfully"
222+
223+
try:
224+
client_v2.get_webhook_details(webhook_name)
225+
except LLMWhispererClientException as e:
226+
assert e.error_message()["message"] == "Webhook details not found"
227+
assert e.error_message()["status_code"] == 404
228+
229+
171230
def assert_error_message(whisper_result):
172231
assert isinstance(whisper_result, dict)
173232
assert whisper_result["status"] == "error"

tests/unit/client_v2_test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
WEBHOOK_URL = "http://test-webhook.com/callback"
22
AUTH_TOKEN = "dummy-auth-token"
33
WEBHOOK_NAME = "test_webhook"
4-
WEBHOOK_RESPONSE = {"status": "success", "message": "Webhook registered successfully"}
4+
WEBHOOK_RESPONSE = {"message": "Webhook registered successfully"}
55
WHISPER_RESPONSE = {"status_code": 200, "extraction": {"result_text": "Test result"}}
66

77

88
def test_register_webhook(mocker, client_v2):
99
mock_send = mocker.patch("requests.Session.send")
1010
mock_response = mocker.MagicMock()
11-
mock_response.status_code = 200
12-
mock_response.text = '{"status": "success", "message": "Webhook registered successfully"}' # noqa: E501
11+
mock_response.status_code = 201
12+
mock_response.text = '{"message": "Webhook registered successfully"}' # noqa: E501
1313
mock_send.return_value = mock_response
1414

1515
response = client_v2.register_webhook(WEBHOOK_URL, AUTH_TOKEN, WEBHOOK_NAME)

0 commit comments

Comments
 (0)