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

Aaq v2 response feedback #614

Merged
merged 4 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
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
Loading