Skip to content

ref(feedback): skip ai titles for spam feedback #97448

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

Merged
merged 3 commits into from
Aug 8, 2025
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
4 changes: 3 additions & 1 deletion src/sentry/feedback/usecases/ingest/create_feedback.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,12 @@ def create_feedback_issue(
event["contexts"]["feedback"], source, is_message_spam
)
issue_fingerprint = [uuid4().hex]

ai_title = None
if should_get_ai_title(project.organization):
if not is_message_spam and should_get_ai_title(project.organization):
ai_title = get_feedback_title_from_seer(feedback_message, project.organization_id)
formatted_title = format_feedback_title(ai_title or feedback_message)

occurrence = IssueOccurrence(
id=uuid4().hex,
event_id=event["event_id"],
Expand Down
4 changes: 3 additions & 1 deletion src/sentry/feedback/usecases/title_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

logger = logging.getLogger(__name__)

SEER_GENERATE_TITLE_URL = f"{settings.SEER_AUTOFIX_URL}/v1/automation/summarize/feedback/title"


class GenerateFeedbackTitleRequest(TypedDict):
"""Corresponds to GenerateFeedbackTitleRequest in Seer."""
Expand Down Expand Up @@ -128,7 +130,7 @@ def make_seer_request(request: GenerateFeedbackTitleRequest) -> bytes:
serialized_request = json.dumps(request)

response = requests.post(
f"{settings.SEER_AUTOFIX_URL}/v1/automation/summarize/feedback/title",
SEER_GENERATE_TITLE_URL,
data=serialized_request,
headers={
"content-type": "application/json;charset=utf-8",
Expand Down
41 changes: 34 additions & 7 deletions tests/sentry/feedback/usecases/ingest/test_create_feedback.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import pytest
import responses
from django.conf import settings

from sentry.feedback.lib.utils import FeedbackCreationSource
from sentry.feedback.usecases.ingest.create_feedback import (
Expand All @@ -19,6 +18,7 @@
MAX_AI_LABELS,
MAX_AI_LABELS_JSON_LENGTH,
)
from sentry.feedback.usecases.title_generation import SEER_GENERATE_TITLE_URL
from sentry.models.group import Group, GroupStatus
from sentry.signals import first_feedback_received, first_new_feedback_received
from sentry.testutils.helpers import Feature
Expand All @@ -28,11 +28,11 @@
from tests.sentry.feedback import create_dummy_openai_response, mock_feedback_event


def mock_seer_response(**kwargs) -> None:
"""Use with @responses.activate to mock Seer API responses."""
def mock_seer_title_response(**kwargs) -> None:
"""Use with @responses.activate to mock Seer title generation response."""
responses.add(
responses.POST,
f"{settings.SEER_AUTOFIX_URL}/v1/automation/summarize/feedback/title",
SEER_GENERATE_TITLE_URL,
**kwargs,
)

Expand Down Expand Up @@ -944,7 +944,7 @@ def test_create_feedback_issue_title_from_seer(
event = mock_feedback_event(default_project.id)
event["contexts"]["feedback"]["message"] = "The login button is broken and the UI is slow"

mock_seer_response(
mock_seer_title_response(
status=200,
body='{"title": "Login Button Issue"}',
)
Expand All @@ -970,7 +970,7 @@ def test_create_feedback_issue_title_from_seer_fallback(
event = mock_feedback_event(default_project.id)
event["contexts"]["feedback"]["message"] = "The login button is broken and the UI is slow"

mock_seer_response(body=Exception("Network Error"))
mock_seer_title_response(body=Exception("Network Error"))
create_feedback_issue(event, default_project, FeedbackCreationSource.NEW_FEEDBACK_ENVELOPE)

assert mock_produce_occurrence_to_kafka.call_count == 1
Expand All @@ -980,6 +980,33 @@ def test_create_feedback_issue_title_from_seer_fallback(
)


@django_db_all
@responses.activate
def test_create_feedback_issue_title_from_seer_skips_if_spam(
default_project,
mock_produce_occurrence_to_kafka,
) -> None:
"""Test title generation endpoint is not called if marked as spam."""
with (
patch("sentry.feedback.usecases.ingest.create_feedback.is_spam", return_value=True),
# XXX: this is not ideal to mock, we should refactor spam and AI processors to their own unit testable function.
patch(
"sentry.feedback.usecases.ingest.create_feedback.spam_detection_enabled",
return_value=True,
),
Feature(
{
"organizations:gen-ai-features": True,
"organizations:user-feedback-ai-titles": True,
}
),
):
event = mock_feedback_event(default_project.id)
create_feedback_issue(event, default_project, FeedbackCreationSource.NEW_FEEDBACK_ENVELOPE)
urls = [call.request.url for call in responses.calls]
assert SEER_GENERATE_TITLE_URL not in urls


@django_db_all
@responses.activate
def test_create_feedback_issue_title_from_seer_none(
Expand All @@ -995,7 +1022,7 @@ def test_create_feedback_issue_title_from_seer_none(
event = mock_feedback_event(default_project.id)
event["contexts"]["feedback"]["message"] = "The login button is broken and the UI is slow"

mock_seer_response(
mock_seer_title_response(
status=200,
body='{"title": ""}',
)
Expand Down
9 changes: 3 additions & 6 deletions tests/sentry/feedback/usecases/test_title_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

import pytest
import responses
from django.conf import settings

from sentry.feedback.usecases.title_generation import (
SEER_GENERATE_TITLE_URL,
GenerateFeedbackTitleRequest,
format_feedback_title,
get_feedback_title_from_seer,
Expand All @@ -22,7 +22,7 @@ def mock_seer_response(**kwargs) -> None:
"""Use with @responses.activate to mock Seer API responses."""
responses.add(
responses.POST,
f"{settings.SEER_AUTOFIX_URL}/v1/automation/summarize/feedback/title",
SEER_GENERATE_TITLE_URL,
**kwargs,
)

Expand Down Expand Up @@ -78,10 +78,7 @@ def test_make_seer_request(self):

assert len(responses.calls) == 1
seer_request = responses.calls[0].request
assert (
seer_request.url
== f"{settings.SEER_AUTOFIX_URL}/v1/automation/summarize/feedback/title"
)
assert seer_request.url == SEER_GENERATE_TITLE_URL
assert seer_request.method == "POST"
assert seer_request.headers["content-type"] == "application/json;charset=utf-8"

Expand Down
Loading