2024-07-02 08:51:59 -07:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
RSpec.describe DiscourseAi::Summarization::SummaryController do
|
|
|
|
describe "#summary" do
|
|
|
|
fab!(:topic) { Fabricate(:topic, highest_post_number: 2) }
|
|
|
|
fab!(:post_1) { Fabricate(:post, topic: topic, post_number: 1) }
|
|
|
|
fab!(:post_2) { Fabricate(:post, topic: topic, post_number: 2) }
|
|
|
|
|
2024-07-04 10:48:18 +10:00
|
|
|
before do
|
|
|
|
assign_fake_provider_to(:ai_summarization_model)
|
|
|
|
SiteSetting.ai_summarization_enabled = true
|
|
|
|
end
|
2024-07-02 08:51:59 -07:00
|
|
|
|
2024-08-13 21:47:47 +10:00
|
|
|
context "when streaming" do
|
|
|
|
it "return a cached summary with json payload and does not trigger job if it exists" do
|
FIX: Make summaries backfill job more resilient. (#1071)
To quickly select backfill candidates without comparing SHAs, we compare the last summarized post to the topic's highest_post_number. However, hiding or deleting a post and adding a small action will update this column, causing the job to stall and re-generate the same summary repeatedly until someone posts a regular reply. On top of this, this is not always true for topics with `best_replies`, as this last reply isn't necessarily included.
Since this is not evident at first glance and each summarization strategy picks its targets differently, I'm opting to simplify the backfill logic and how we track potential candidates.
The first step is dropping `content_range`, which serves no purpose and it's there because summary caching was supposed to work differently at the beginning. So instead, I'm replacing it with a column called `highest_target_number`, which tracks `highest_post_number` for topics and could track other things like channel's `message_count` in the future.
Now that we have this column when selecting every potential backfill candidate, we'll check if the summary is truly outdated by comparing the SHAs, and if it's not, we just update the column and move on
2025-01-16 09:42:53 -03:00
|
|
|
summary = Fabricate(:ai_summary, target: topic)
|
2024-08-13 21:47:47 +10:00
|
|
|
sign_in(Fabricate(:admin))
|
|
|
|
|
|
|
|
get "/discourse-ai/summarization/t/#{topic.id}.json?stream=true"
|
|
|
|
|
|
|
|
expect(response.status).to eq(200)
|
|
|
|
expect(Jobs::StreamTopicAiSummary.jobs.size).to eq(0)
|
|
|
|
|
FIX: Make summaries backfill job more resilient. (#1071)
To quickly select backfill candidates without comparing SHAs, we compare the last summarized post to the topic's highest_post_number. However, hiding or deleting a post and adding a small action will update this column, causing the job to stall and re-generate the same summary repeatedly until someone posts a regular reply. On top of this, this is not always true for topics with `best_replies`, as this last reply isn't necessarily included.
Since this is not evident at first glance and each summarization strategy picks its targets differently, I'm opting to simplify the backfill logic and how we track potential candidates.
The first step is dropping `content_range`, which serves no purpose and it's there because summary caching was supposed to work differently at the beginning. So instead, I'm replacing it with a column called `highest_target_number`, which tracks `highest_post_number` for topics and could track other things like channel's `message_count` in the future.
Now that we have this column when selecting every potential backfill candidate, we'll check if the summary is truly outdated by comparing the SHAs, and if it's not, we just update the column and move on
2025-01-16 09:42:53 -03:00
|
|
|
response_summary = response.parsed_body
|
|
|
|
expect(response_summary.dig("ai_topic_summary", "summarized_text")).to eq(
|
|
|
|
summary.summarized_text,
|
|
|
|
)
|
2024-08-13 21:47:47 +10:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-07-02 08:51:59 -07:00
|
|
|
context "for anons" do
|
|
|
|
it "returns a 404 if there is no cached summary" do
|
|
|
|
get "/discourse-ai/summarization/t/#{topic.id}.json"
|
|
|
|
|
|
|
|
expect(response.status).to eq(404)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns a cached summary" do
|
FIX: Make summaries backfill job more resilient. (#1071)
To quickly select backfill candidates without comparing SHAs, we compare the last summarized post to the topic's highest_post_number. However, hiding or deleting a post and adding a small action will update this column, causing the job to stall and re-generate the same summary repeatedly until someone posts a regular reply. On top of this, this is not always true for topics with `best_replies`, as this last reply isn't necessarily included.
Since this is not evident at first glance and each summarization strategy picks its targets differently, I'm opting to simplify the backfill logic and how we track potential candidates.
The first step is dropping `content_range`, which serves no purpose and it's there because summary caching was supposed to work differently at the beginning. So instead, I'm replacing it with a column called `highest_target_number`, which tracks `highest_post_number` for topics and could track other things like channel's `message_count` in the future.
Now that we have this column when selecting every potential backfill candidate, we'll check if the summary is truly outdated by comparing the SHAs, and if it's not, we just update the column and move on
2025-01-16 09:42:53 -03:00
|
|
|
summary = Fabricate(:ai_summary, target: topic)
|
2024-07-02 08:51:59 -07:00
|
|
|
get "/discourse-ai/summarization/t/#{topic.id}.json"
|
|
|
|
|
|
|
|
expect(response.status).to eq(200)
|
|
|
|
|
FIX: Make summaries backfill job more resilient. (#1071)
To quickly select backfill candidates without comparing SHAs, we compare the last summarized post to the topic's highest_post_number. However, hiding or deleting a post and adding a small action will update this column, causing the job to stall and re-generate the same summary repeatedly until someone posts a regular reply. On top of this, this is not always true for topics with `best_replies`, as this last reply isn't necessarily included.
Since this is not evident at first glance and each summarization strategy picks its targets differently, I'm opting to simplify the backfill logic and how we track potential candidates.
The first step is dropping `content_range`, which serves no purpose and it's there because summary caching was supposed to work differently at the beginning. So instead, I'm replacing it with a column called `highest_target_number`, which tracks `highest_post_number` for topics and could track other things like channel's `message_count` in the future.
Now that we have this column when selecting every potential backfill candidate, we'll check if the summary is truly outdated by comparing the SHAs, and if it's not, we just update the column and move on
2025-01-16 09:42:53 -03:00
|
|
|
response_summary = response.parsed_body
|
|
|
|
expect(response_summary.dig("ai_topic_summary", "summarized_text")).to eq(
|
|
|
|
summary.summarized_text,
|
|
|
|
)
|
2024-07-02 08:51:59 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when the user is a member of an allowlisted group" do
|
|
|
|
fab!(:user) { Fabricate(:leader) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
Group.find(Group::AUTO_GROUPS[:trust_level_3]).add(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns a 404 if there is no topic" do
|
|
|
|
invalid_topic_id = 999
|
|
|
|
|
|
|
|
get "/discourse-ai/summarization/t/#{invalid_topic_id}.json"
|
|
|
|
|
|
|
|
expect(response.status).to eq(404)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns a 403 if not allowed to see the topic" do
|
|
|
|
pm = Fabricate(:private_message_topic)
|
|
|
|
|
|
|
|
get "/discourse-ai/summarization/t/#{pm.id}.json"
|
|
|
|
|
|
|
|
expect(response.status).to eq(403)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns a summary" do
|
|
|
|
summary_text = "This is a summary"
|
|
|
|
DiscourseAi::Completions::Llm.with_prepared_responses([summary_text]) do
|
|
|
|
get "/discourse-ai/summarization/t/#{topic.id}.json"
|
|
|
|
|
|
|
|
expect(response.status).to eq(200)
|
FIX: Make summaries backfill job more resilient. (#1071)
To quickly select backfill candidates without comparing SHAs, we compare the last summarized post to the topic's highest_post_number. However, hiding or deleting a post and adding a small action will update this column, causing the job to stall and re-generate the same summary repeatedly until someone posts a regular reply. On top of this, this is not always true for topics with `best_replies`, as this last reply isn't necessarily included.
Since this is not evident at first glance and each summarization strategy picks its targets differently, I'm opting to simplify the backfill logic and how we track potential candidates.
The first step is dropping `content_range`, which serves no purpose and it's there because summary caching was supposed to work differently at the beginning. So instead, I'm replacing it with a column called `highest_target_number`, which tracks `highest_post_number` for topics and could track other things like channel's `message_count` in the future.
Now that we have this column when selecting every potential backfill candidate, we'll check if the summary is truly outdated by comparing the SHAs, and if it's not, we just update the column and move on
2025-01-16 09:42:53 -03:00
|
|
|
response_summary = response.parsed_body["ai_topic_summary"]
|
|
|
|
summary = AiSummary.last
|
|
|
|
|
|
|
|
expect(summary.summarized_text).to eq(summary_text)
|
|
|
|
expect(response_summary["summarized_text"]).to eq(summary.summarized_text)
|
|
|
|
expect(response_summary["algorithm"]).to eq("fake")
|
|
|
|
expect(response_summary["outdated"]).to eq(false)
|
|
|
|
expect(response_summary["can_regenerate"]).to eq(true)
|
|
|
|
expect(response_summary["new_posts_since_summary"]).to be_zero
|
2024-07-02 08:51:59 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it "signals the summary is outdated" do
|
|
|
|
get "/discourse-ai/summarization/t/#{topic.id}.json"
|
|
|
|
|
|
|
|
Fabricate(:post, topic: topic, post_number: 3)
|
|
|
|
topic.update!(highest_post_number: 3)
|
|
|
|
|
|
|
|
get "/discourse-ai/summarization/t/#{topic.id}.json"
|
|
|
|
expect(response.status).to eq(200)
|
|
|
|
summary = response.parsed_body["ai_topic_summary"]
|
|
|
|
|
|
|
|
expect(summary["outdated"]).to eq(true)
|
|
|
|
expect(summary["new_posts_since_summary"]).to eq(1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when the user is not a member of an allowlisted group" do
|
|
|
|
fab!(:user)
|
|
|
|
|
|
|
|
before { sign_in(user) }
|
|
|
|
|
|
|
|
it "return a 404 if there is no cached summary" do
|
|
|
|
get "/discourse-ai/summarization/t/#{topic.id}.json"
|
|
|
|
|
|
|
|
expect(response.status).to eq(404)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns a cached summary" do
|
FIX: Make summaries backfill job more resilient. (#1071)
To quickly select backfill candidates without comparing SHAs, we compare the last summarized post to the topic's highest_post_number. However, hiding or deleting a post and adding a small action will update this column, causing the job to stall and re-generate the same summary repeatedly until someone posts a regular reply. On top of this, this is not always true for topics with `best_replies`, as this last reply isn't necessarily included.
Since this is not evident at first glance and each summarization strategy picks its targets differently, I'm opting to simplify the backfill logic and how we track potential candidates.
The first step is dropping `content_range`, which serves no purpose and it's there because summary caching was supposed to work differently at the beginning. So instead, I'm replacing it with a column called `highest_target_number`, which tracks `highest_post_number` for topics and could track other things like channel's `message_count` in the future.
Now that we have this column when selecting every potential backfill candidate, we'll check if the summary is truly outdated by comparing the SHAs, and if it's not, we just update the column and move on
2025-01-16 09:42:53 -03:00
|
|
|
summary = Fabricate(:ai_summary, target: topic)
|
2024-07-02 08:51:59 -07:00
|
|
|
|
|
|
|
get "/discourse-ai/summarization/t/#{topic.id}.json"
|
|
|
|
|
|
|
|
expect(response.status).to eq(200)
|
|
|
|
|
FIX: Make summaries backfill job more resilient. (#1071)
To quickly select backfill candidates without comparing SHAs, we compare the last summarized post to the topic's highest_post_number. However, hiding or deleting a post and adding a small action will update this column, causing the job to stall and re-generate the same summary repeatedly until someone posts a regular reply. On top of this, this is not always true for topics with `best_replies`, as this last reply isn't necessarily included.
Since this is not evident at first glance and each summarization strategy picks its targets differently, I'm opting to simplify the backfill logic and how we track potential candidates.
The first step is dropping `content_range`, which serves no purpose and it's there because summary caching was supposed to work differently at the beginning. So instead, I'm replacing it with a column called `highest_target_number`, which tracks `highest_post_number` for topics and could track other things like channel's `message_count` in the future.
Now that we have this column when selecting every potential backfill candidate, we'll check if the summary is truly outdated by comparing the SHAs, and if it's not, we just update the column and move on
2025-01-16 09:42:53 -03:00
|
|
|
response_summary = response.parsed_body
|
|
|
|
expect(response_summary.dig("ai_topic_summary", "summarized_text")).to eq(
|
|
|
|
summary.summarized_text,
|
|
|
|
)
|
2024-07-02 08:51:59 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|