Skip to content

Commit

Permalink
Merge pull request #614 from praekeltfoundation/aaq-v2-response-feedback
Browse files Browse the repository at this point in the history
Aaq v2 response feedback
  • Loading branch information
Hlamallama authored Aug 5, 2024
2 parents c70fcfc + c1fdf7c commit 0db6510
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 2 deletions.
9 changes: 9 additions & 0 deletions aaq/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ def validate(self, data):
return data


class ResponseFeedbackSerializer(serializers.Serializer):
feedback_secret_key = serializers.CharField(required=True)
feedback_sentiment = serializers.ChoiceField(
required=False, choices=["negative", "positive"]
)
feedback_text = serializers.CharField(required=False)
query_id = serializers.IntegerField(required=True)


class SearchSerializer(serializers.Serializer):
query_text = serializers.CharField(required=True)
generate_llm_response = serializers.BooleanField(required=False)
Expand Down
28 changes: 28 additions & 0 deletions aaq/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,31 @@ def send_feedback_task(secret_key, inbound_id, feedback_type, **kwargs):
}
response = requests.request("PUT", url, json=data, headers=headers)
response.raise_for_status()


@app.task(
autoretry_for=(RequestException, SoftTimeLimitExceeded),
retry_backoff=True,
max_retries=15,
acks_late=True,
soft_time_limit=10,
time_limit=15,
)
def send_feedback_task_v2(feedback_secret_key, query_id, **kwargs):
data = {
"feedback_secret_key": feedback_secret_key,
"query_id": query_id,
}

if "feedback_sentiment" in kwargs:
data["feedback_sentiment"] = kwargs["feedback_sentiment"]
if "feedback_text" in kwargs:
data["feedback_text"] = kwargs["feedback_text"]

url = urljoin(settings.AAQ_V2_API_URL, "/response-feedback")
headers = {
"Authorization": settings.AAQ_V2_AUTH,
"Content-Type": "application/json",
}
response = requests.post(url, json=data, headers=headers)
response.raise_for_status()
7 changes: 7 additions & 0 deletions aaq/tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ def call_add_feedback_task(self, request):
}
return (202, {}, json.dumps(resp_body))

def call_add_feedback_task_v2(self, request):
resp_body = {
"task_added": "True",
}

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


class FakeAaqApi:
def post_search(self, request):
Expand Down
34 changes: 33 additions & 1 deletion aaq/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import responses
from django.test import TestCase

from aaq.tasks import send_feedback_task
from aaq.tasks import send_feedback_task, send_feedback_task_v2


class AddFeedbackTaskTest(TestCase):
Expand Down Expand Up @@ -62,3 +62,35 @@ def test_add_feedback_page_task(self):

self.assertEqual(request.request.url, "http://aaqcore/inbound/feedback")
self.assertEqual(json.loads(request.request.body), data)


class ResponseFeedbackTaskTest(TestCase):
@responses.activate
def test_response_feedback_task(self):
data = {
"feedback_secret_key": "secret 12345",
"query_id": 1,
"feedback_sentiment": "negative",
"feedback_text": "Not helpful",
}

responses.add(
responses.POST,
"http://aaq_v2/response-feedback",
json={},
status=200,
)

kwargs = {}
kwargs["feedback_sentiment"] = "negative"
kwargs["feedback_text"] = "Not helpful"
send_feedback_task_v2.delay(
"secret 12345",
1,
**kwargs,
)

[request] = responses.calls

self.assertEqual(request.request.url, "http://aaq_v2/response-feedback")
self.assertEqual(json.loads(request.request.body), data)
80 changes: 80 additions & 0 deletions aaq/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,86 @@ def test_not_urgent(self):
assert response.json() == {"urgency_score": 0.0}


class ResponseFeedbackViewTests(APITestCase):
url = reverse("aaq-response-feedback")

@responses.activate
def test_response_feedback_view(self):
"""Test that we can submit response feedback on an FAQ"""
payload = {
"feedback_secret_key": "secret-key-12345-abcde",
"query_id": 1,
"feedback_sentiment": "negative",
"feedback_text": "Not helpful",
}
user = get_user_model().objects.create_user("test")
self.client.force_authenticate(user)
fakeTask = FakeTask()
responses.add_callback(
responses.POST,
"http://aaq_v2/response-feedback",
callback=fakeTask.call_add_feedback_task_v2,
content_type="application/json",
)

response = self.client.post(self.url, data=payload, format="json")

assert response.status_code == 200

def test_response_feedback_invalid_view(self):
"""Test that we can submit response feedback"""
payload = json.dumps(
{
"feedback_secret_key": "secret-key-12345-abcde",
}
)
user = get_user_model().objects.create_user("test")
self.client.force_authenticate(user)
fakeTask = FakeTask()
responses.add_callback(
responses.POST,
"http://aaq_v2/response-feedback",
callback=fakeTask.call_add_feedback_task_v2,
content_type="application/json",
)

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

assert response.status_code == 400
assert response.json() == {"query_id": ["This field is required."]}

def test_response_feedback_invalid_sentiment_view(self):
"""Test that we can submit response feedback"""
payload = json.dumps(
{
"feedback_secret_key": "secret-key-12345-abcde",
"query_id": 1,
"feedback_sentiment": "sentiment",
"feedback_text": "Not helpful",
}
)
user = get_user_model().objects.create_user("test")
self.client.force_authenticate(user)
fakeTask = FakeTask()
responses.add_callback(
responses.POST,
"http://aaq_v2/response-feedback",
callback=fakeTask.call_add_feedback_task_v2,
content_type="application/json",
)

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

assert response.status_code == 400
assert response.json() == {
"feedback_sentiment": ['"sentiment" is not a valid choice.']
}


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

Expand Down
5 changes: 5 additions & 0 deletions aaq/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
views.check_urgency,
name="aaq-check-urgency",
),
re_path(
r"^api/v2/response-feedback",
views.response_feedback,
name="aaq-response-feedback",
),
re_path(
r"^api/v2/search",
views.search,
Expand Down
25 changes: 24 additions & 1 deletion aaq/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
from aaq.serializers import (
AddFeedbackSerializer,
InboundCheckSerializer,
ResponseFeedbackSerializer,
SearchSerializer,
UrgencyCheckSerializer,
)

from .tasks import send_feedback_task
from .tasks import send_feedback_task, send_feedback_task_v2

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -119,6 +120,28 @@ def check_urgency(request, *args, **kwargs):
return Response(return_data, status=status.HTTP_202_ACCEPTED)


@api_view(("POST",))
@renderer_classes((JSONRenderer,))
def response_feedback(request, *args, **kwargs):

serializer = ResponseFeedbackSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
feedback_secret_key = serializer.validated_data["feedback_secret_key"]
query_id = serializer.validated_data["query_id"]

task_kwargs = {}
if "feedback_sentiment" in serializer.validated_data:
task_kwargs["feedback_sentiment"] = serializer.validated_data[
"feedback_sentiment"
]
if "feedback_text" in serializer.validated_data:
task_kwargs["feedback_text"] = serializer.validated_data["feedback_text"]

send_feedback_task_v2.delay(feedback_secret_key, query_id, **task_kwargs)

return Response(status=status.HTTP_200_OK)


@api_view(("POST",))
@renderer_classes((JSONRenderer,))
def search(request, *args, **kwargs):
Expand Down

0 comments on commit 0db6510

Please sign in to comment.