Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AAQ v2 faq search endpoint #613

Merged
merged 10 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like its just recreating the dict exactly how we got it from AAQ and returning it?

Shouldn't we build a message here like AAQ v1?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hlamallama Have have you seen this feedback?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DevChima yes, i've implemeted the feedback from Eric

"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
Loading