Skip to content

Commit

Permalink
Merge pull request #613 from praekeltfoundation/aaq-v2
Browse files Browse the repository at this point in the history
Add AAQ v2 faq search endpoint
  • Loading branch information
Hlamallama authored Aug 5, 2024
2 parents 3369830 + bcc66f4 commit c70fcfc
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 1 deletion.
6 changes: 6 additions & 0 deletions aaq/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,9 @@ def validate(self, data):
)

return data


class SearchSerializer(serializers.Serializer):
query_text = serializers.CharField(required=True)
generate_llm_response = serializers.BooleanField(required=False)
query_metadata = serializers.JSONField(required=False)
39 changes: 39 additions & 0 deletions aaq/tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,42 @@ def call_add_feedback_task(self, request):
"task_added": "True",
}
return (202, {}, json.dumps(resp_body))


class FakeAaqApi:
def post_search(self, request):
resp_body = {
"debug_info": {"example": "debug-info"},
"feedback_secret_key": "secret-key-12345-abcde",
"llm_response": None,
"query_id": 1,
"search_results": {
"0": {
"distance": 0.1,
"id": 23,
"text": "Example content text",
"title": "Example content title",
},
"1": {
"distance": 0.2,
"id": 12,
"text": "Another example content text",
"title": "Another example content title",
},
},
"state": "final",
}

return (200, {}, json.dumps(resp_body))

def post_search_return_empty(self, request):
resp_body = {
"debug_info": {"example": "debug-info"},
"feedback_secret_key": "secret-key-12345-abcde",
"llm_response": None,
"query_id": 1,
"search_results": {},
"state": "final",
}

return (200, {}, json.dumps(resp_body))
102 changes: 101 additions & 1 deletion aaq/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from rest_framework import status
from rest_framework.test import APITestCase

from .helpers import FakeAaqCoreApi, FakeAaqUdApi, FakeTask
from .helpers import FakeAaqApi, FakeAaqCoreApi, FakeAaqUdApi, FakeTask


class GetFirstPageViewTests(APITestCase):
Expand Down Expand Up @@ -264,3 +264,103 @@ def test_not_urgent(self):
)

assert response.json() == {"urgency_score": 0.0}


class SearchViewTests(APITestCase):
url = reverse("aaq-search")

@responses.activate
def test_search(self):
"""
Test that search returns data.
"""

user = get_user_model().objects.create_user("test")
self.client.force_authenticate(user)
fakeAaqApi = FakeAaqApi()
responses.add_callback(
responses.POST,
"http://aaq_v2/search",
callback=fakeAaqApi.post_search,
content_type="application/json",
)

payload = json.dumps(
{
"generate_llm_response": False,
"query_metadata": {"some_key": "query_metadata"},
"query_text": "Breastfeeding",
}
)

response = self.client.post(
self.url, data=payload, content_type="application/json"
)

self.assertEqual(response.status_code, 200)
self.assertIn("message", response.data)
self.assertIn("body", response.data)
self.assertIn("query_id", response.data)
self.assertIn("feedback_secret_key", response.data)

assert response.json() == {
"message": "*0* - Example content title\n*1* -"
" Another example content title",
"body": {
"0": {"text": "Example content text", "id": 23},
"1": {"text": "Another example content text", "id": 12},
},
"feedback_secret_key": "secret-key-12345-abcde",
"query_id": 1,
}

@responses.activate
def test_search_gibberish(self):
"""
Check that we get a response with an empty list in the search results part
"""
user = get_user_model().objects.create_user("test")
self.client.force_authenticate(user)
fakeAaqApi = FakeAaqApi()
responses.add_callback(
responses.POST,
"http://aaq_v2/search",
callback=fakeAaqApi.post_search_return_empty,
content_type="application/json",
)

payload = json.dumps(
{
"generate_llm_response": False,
"query_metadata": {"some_key": "query_metadata"},
"query_text": "yjyvcgrfeuyikbjmfb",
}
)

response = self.client.post(
self.url, data=payload, content_type="application/json"
)

assert response.json() == {
"message": "Gibberish Detected",
"body": {},
"feedback_secret_key": "secret-key-12345-abcde",
"query_id": 1,
}

@responses.activate
def test_search_invalid_request_body(self):
"""
Test search valid request.
"""
user = get_user_model().objects.create_user("test")
self.client.force_authenticate(user)

payload = json.dumps({})

response = self.client.post(
self.url, data=payload, content_type="application/json"
)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.json(), {"query_text": ["This field is required."]})
5 changes: 5 additions & 0 deletions aaq/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,9 @@
views.check_urgency,
name="aaq-check-urgency",
),
re_path(
r"^api/v2/search",
views.search,
name="aaq-search",
),
]
57 changes: 57 additions & 0 deletions aaq/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from aaq.serializers import (
AddFeedbackSerializer,
InboundCheckSerializer,
SearchSerializer,
UrgencyCheckSerializer,
)

Expand Down Expand Up @@ -116,3 +117,59 @@ def check_urgency(request, *args, **kwargs):

return_data = json_msg
return Response(return_data, status=status.HTTP_202_ACCEPTED)


@api_view(("POST",))
@renderer_classes((JSONRenderer,))
def search(request, *args, **kwargs):
serializer = SearchSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
query_text = serializer.validated_data["query_text"]
generate_llm_response = serializer.validated_data["generate_llm_response"]
query_metadata = serializer.validated_data["query_metadata"]
url = urllib.parse.urljoin(settings.AAQ_V2_API_URL, "search")
payload = {
"query_text": query_text,
"generate_llm_response": generate_llm_response,
"query_metadata": query_metadata,
}
headers = {
"Authorization": settings.AAQ_V2_AUTH,
"Content-Type": "application/json",
}

response = requests.request("POST", url, json=payload, headers=headers)

query_id = response.json()["query_id"]
feedback_secret_key = response.json()["feedback_secret_key"]
search_results = response.json()["search_results"]

if search_results == {}:
json_msg = {
"message": "Gibberish Detected",
"body": {},
"feedback_secret_key": feedback_secret_key,
"query_id": query_id,
}
return Response(json_msg, status=status.HTTP_200_OK)

json_msg = {}
body_content = {}
message_titles = []

for key, value in search_results.items():
text = value["text"]
id = value["id"]
title = value["title"]

body_content[key] = {"text": text, "id": id}
message_titles.append(f"*{key}* - {title}")

json_msg = {
"message": "\n".join(message_titles),
"body": body_content,
"feedback_secret_key": feedback_secret_key,
"query_id": query_id,
}

return Response(json_msg, status=status.HTTP_200_OK)
4 changes: 4 additions & 0 deletions ndoh_hub/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,10 @@
AAQ_UD_API_URL = env.str("AAQ_UD_API_URL", None)
AAQ_UD_INBOUND_CHECK_AUTH = env.str("AAQ_UD_INBOUND_CHECK_AUTH", None)

# AAQ V2
AAQ_V2_API_URL = env.str("AAQ_V2_API_URL", None)
AAQ_V2_AUTH = env.str("AAQ_V2_AUTH", None)

ALERT_OPTOUT_PHRASE = env.str("ALERT_OPTOUT_PHRASE", "Opt out of alerts")

WHATSAPP_TEMPLATE_SEND_TIMEOUT_HOURS = env.int(
Expand Down
2 changes: 2 additions & 0 deletions ndoh_hub/testsettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

AAQ_CORE_API_URL = "http://aaqcore"
AAQ_UD_API_URL = "http://aaqud"
AAQ_V2_API_URL = "http://aaq_v2"


ADA_EDC_STUDY_URL = "http://castor"
ADA_EDC_STUDY_ID = "test-study-id"
Expand Down

0 comments on commit c70fcfc

Please sign in to comment.