FEATURE: Calculate gists from non hot topics too (#958)

Also renames some settings to remove 'hot' references.
This commit is contained in:
Rafael dos Santos Silva 2024-11-26 13:44:12 -03:00 committed by GitHub
parent 54f2d34ccb
commit 23193ee6f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 61 additions and 218 deletions

View File

@ -1,23 +1,20 @@
# frozen_string_literal: true # frozen_string_literal: true
module ::Jobs module ::Jobs
class UpdateHotTopicGist < ::Jobs::Base class FastTrackTopicGist < ::Jobs::Base
sidekiq_options retry: false sidekiq_options retry: false
def execute(args) def execute(args)
return if !SiteSetting.discourse_ai_enabled return if !SiteSetting.discourse_ai_enabled
return if !SiteSetting.ai_summarization_enabled return if !SiteSetting.ai_summarization_enabled
return if SiteSetting.ai_summarize_max_hot_topics_gists_per_batch.zero? return if !SiteSetting.ai_summary_gists_enabled
topic = Topic.find_by(id: args[:topic_id]) topic = Topic.find_by(id: args[:topic_id])
return if topic.blank? return if topic.blank?
return if !TopicHotScore.where(topic: topic).exists?
summarizer = DiscourseAi::Summarization.topic_gist(topic) summarizer = DiscourseAi::Summarization.topic_gist(topic)
gist = summarizer.existing_summary gist = summarizer.existing_summary
return if gist.blank? return if gist.present? && !gist.outdated
return if !gist.outdated
summarizer.force_summarize(Discourse.system_user) summarizer.force_summarize(Discourse.system_user)
end end

View File

@ -1,22 +0,0 @@
# frozen_string_literal: true
module ::Jobs
class HotTopicsGistBatch < ::Jobs::Base
def execute(_args)
return if !SiteSetting.discourse_ai_enabled
return if !SiteSetting.ai_summarization_enabled
return if SiteSetting.ai_summarize_max_hot_topics_gists_per_batch.zero?
Topic
.joins("JOIN topic_hot_scores on topics.id = topic_hot_scores.topic_id")
.order("topic_hot_scores.score DESC")
.limit(SiteSetting.ai_summarize_max_hot_topics_gists_per_batch)
.each do |topic|
summarizer = DiscourseAi::Summarization.topic_gist(topic)
gist = summarizer.existing_summary
summarizer.force_summarize(Discourse.system_user) if gist.blank? || gist.outdated
end
end
end
end

View File

@ -19,6 +19,8 @@ module ::Jobs
DiscourseAi::Summarization.topic_summary(topic).force_summarize(system_user) DiscourseAi::Summarization.topic_summary(topic).force_summarize(system_user)
end end
return unless SiteSetting.ai_summary_gists_enabled
gist_t = AiSummary.summary_types[:gist] gist_t = AiSummary.summary_types[:gist]
backfill_candidates(gist_t) backfill_candidates(gist_t)
.limit(current_budget(gist_t)) .limit(current_budget(gist_t))

View File

@ -85,8 +85,8 @@ de:
ai_summarization_model: "Modell, das für die Zusammenfassung verwendet werden soll." ai_summarization_model: "Modell, das für die Zusammenfassung verwendet werden soll."
ai_custom_summarization_allowed_groups: "Gruppen, die neue Zusammenfassungen erstellen dürfen." ai_custom_summarization_allowed_groups: "Gruppen, die neue Zusammenfassungen erstellen dürfen."
ai_pm_summarization_allowed_groups: "Gruppen können Zusammenfassungen in PMs erstellen und ansehen." ai_pm_summarization_allowed_groups: "Gruppen können Zusammenfassungen in PMs erstellen und ansehen."
ai_summarize_max_hot_topics_gists_per_batch: "Nach der Aktualisierung der Themen in der angesagten Liste erstellen wir kurze Zusammenfassungen der ersten N Themen. (Deaktiviert, wenn 0)" ai_summary_gists_enabled: "Nach der Aktualisierung der Themen in der angesagten Liste erstellen wir kurze Zusammenfassungen der ersten N Themen. (Deaktiviert, wenn 0)"
ai_hot_topic_gists_allowed_groups: "Gruppen, die die wichtigsten Themen in der Liste der aktuellen Themen sehen dürfen." ai_summary_gists_allowed_groups: "Gruppen, die die wichtigsten Themen in der Liste der aktuellen Themen sehen dürfen."
ai_summary_backfill_maximum_topics_per_hour: "Anzahl der Themenzusammenfassungen, die pro Stunde aufgefüllt werden müssen." ai_summary_backfill_maximum_topics_per_hour: "Anzahl der Themenzusammenfassungen, die pro Stunde aufgefüllt werden müssen."
ai_bot_enabled: "Aktiviere das KI-Bot-Modul." ai_bot_enabled: "Aktiviere das KI-Bot-Modul."
ai_bot_enable_chat_warning: "Zeigt eine Warnung an, wenn der PN-Chat initiiert wird. Kann durch Bearbeiten der Übersetzungszeichenfolge überschrieben werden: discourse_ai.ai_bot.pm_warning" ai_bot_enable_chat_warning: "Zeigt eine Warnung an, wenn der PN-Chat initiiert wird. Kann durch Bearbeiten der Übersetzungszeichenfolge überschrieben werden: discourse_ai.ai_bot.pm_warning"
@ -372,7 +372,7 @@ de:
endpoints: endpoints:
not_configured: "%{display_name} (nicht konfiguriert)" not_configured: "%{display_name} (nicht konfiguriert)"
configuration_hint: configuration_hint:
one: "Vergewissere dich, dass die Einstellung \"%{settings}\" konfiguriert wurde." one: 'Vergewissere dich, dass die Einstellung "%{settings}" konfiguriert wurde.'
other: "Vergewissere dich, dass diese Einstellungen konfiguriert wurden: %{settings}" other: "Vergewissere dich, dass diese Einstellungen konfiguriert wurden: %{settings}"
delete_failed: delete_failed:
one: "Wir konnten dieses Modell nicht löschen, weil es von %{settings} verwendet wird. Aktualisiere die Einstellung und versuche es erneut." one: "Wir konnten dieses Modell nicht löschen, weil es von %{settings} verwendet wird. Aktualisiere die Einstellung und versuche es erneut."

View File

@ -86,8 +86,8 @@ en:
ai_summarization_model: "Model to use for summarization." ai_summarization_model: "Model to use for summarization."
ai_custom_summarization_allowed_groups: "Groups allowed to use create new summaries." ai_custom_summarization_allowed_groups: "Groups allowed to use create new summaries."
ai_pm_summarization_allowed_groups: "Groups allowed to create and view summaries in PMs." ai_pm_summarization_allowed_groups: "Groups allowed to create and view summaries in PMs."
ai_summarize_max_hot_topics_gists_per_batch: "After updating topics in the hot list, we'll generate brief summaries of the first N ones. (Disabled when 0)" ai_summary_gists_enabled: "Generate brief summaries of latest replies in topics automatically."
ai_hot_topic_gists_allowed_groups: "Groups allowed to see gists in the hot topics list." ai_summary_gists_allowed_groups: "Groups allowed to see gists in the hot topics list."
ai_summary_backfill_maximum_topics_per_hour: "Number of topic summaries to backfill per hour." ai_summary_backfill_maximum_topics_per_hour: "Number of topic summaries to backfill per hour."
ai_bot_enabled: "Enable the AI Bot module." ai_bot_enabled: "Enable the AI Bot module."

View File

@ -84,8 +84,8 @@ he:
ai_summarization_model: "מודל לשימוש לסיכום." ai_summarization_model: "מודל לשימוש לסיכום."
ai_custom_summarization_allowed_groups: "קבוצות שמורשות להשתמש ליצירת סיכומים חדשים." ai_custom_summarization_allowed_groups: "קבוצות שמורשות להשתמש ליצירת סיכומים חדשים."
ai_pm_summarization_allowed_groups: "קבוצות שמורשות ליצור ולצפות בתקצירים בהודעות פרטיות." ai_pm_summarization_allowed_groups: "קבוצות שמורשות ליצור ולצפות בתקצירים בהודעות פרטיות."
ai_summarize_max_hot_topics_gists_per_batch: "לאחר עדכון הנושאים ברשימה החמה, נייצר תקצירים של N הראשונים. (0 להשבתה)" ai_summary_gists_enabled: "לאחר עדכון הנושאים ברשימה החמה, נייצר תקצירים של N הראשונים. (0 להשבתה)"
ai_hot_topic_gists_allowed_groups: "קבוצות שמורשות לראות gists ברשימת הנושאים החמים." ai_summary_gists_allowed_groups: "קבוצות שמורשות לראות gists ברשימת הנושאים החמים."
ai_summary_backfill_maximum_topics_per_hour: "מספר תקצירי הנושאים למילוי חוזר בשעה." ai_summary_backfill_maximum_topics_per_hour: "מספר תקצירי הנושאים למילוי חוזר בשעה."
ai_bot_enabled: "הפעלת מודול בוט הבינה המלאכותית." ai_bot_enabled: "הפעלת מודול בוט הבינה המלאכותית."
ai_bot_enable_chat_warning: "הצגת אזהרה עם פתיחת שיח הודעות פרטיות. אפשר לדרוס את זה על ידי עריכת מחרוזת התרגום: discourse_ai.ai_bot.pm_warning" ai_bot_enable_chat_warning: "הצגת אזהרה עם פתיחת שיח הודעות פרטיות. אפשר לדרוס את זה על ידי עריכת מחרוזת התרגום: discourse_ai.ai_bot.pm_warning"
@ -106,7 +106,7 @@ he:
reports: reports:
overall_sentiment: overall_sentiment:
title: "רגש כללי" title: "רגש כללי"
description: 'התרשים משווה את מספר הפוסטים שמסווגים כחיוביים או שליליים. אלו מחושבים כאשר ניקוד חיובי או שלילי הוא גדול מהדף הניוקוד המוגדר. משמעות הדבר היא שפוסטים נייטרליים לא מופיעים. הודעות פרטיות מוחרגות גם כן. מסווגות עם „cardiffnlp/twitter-roberta-base-sentiment-latest”' description: "התרשים משווה את מספר הפוסטים שמסווגים כחיוביים או שליליים. אלו מחושבים כאשר ניקוד חיובי או שלילי הוא גדול מהדף הניוקוד המוגדר. משמעות הדבר היא שפוסטים נייטרליים לא מופיעים. הודעות פרטיות מוחרגות גם כן. מסווגות עם „cardiffnlp/twitter-roberta-base-sentiment-latest”"
xaxis: "חיובי(%)" xaxis: "חיובי(%)"
yaxis: "תאריך" yaxis: "תאריך"
emotion_anger: emotion_anger:

View File

@ -84,8 +84,8 @@ uk:
ai_summarization_model: "Модель для узагальнення." ai_summarization_model: "Модель для узагальнення."
ai_custom_summarization_allowed_groups: "Групи, яким дозволено створювати нові зведення." ai_custom_summarization_allowed_groups: "Групи, яким дозволено створювати нові зведення."
ai_pm_summarization_allowed_groups: "Групи дозволили створювати та переглядати підсумки в особистих повідомленнях." ai_pm_summarization_allowed_groups: "Групи дозволили створювати та переглядати підсумки в особистих повідомленнях."
ai_summarize_max_hot_topics_gists_per_batch: "Після оновлення тем у гарячому списку ми згенеруємо короткі підсумки перших N. (Вимкнено, коли 0)" ai_summary_gists_enabled: "Після оновлення тем у гарячому списку ми згенеруємо короткі підсумки перших N. (Вимкнено, коли 0)"
ai_hot_topic_gists_allowed_groups: "Групи, яким дозволено бачити суть у списку гарячих тем." ai_summary_gists_allowed_groups: "Групи, яким дозволено бачити суть у списку гарячих тем."
ai_summary_backfill_maximum_topics_per_hour: "Кількість підсумків тем для заповнення на годину." ai_summary_backfill_maximum_topics_per_hour: "Кількість підсумків тем для заповнення на годину."
ai_bot_enabled: "Увімкніть модуль AI Bot." ai_bot_enabled: "Увімкніть модуль AI Bot."
ai_bot_enable_chat_warning: "Відображати попередження, коли починається чат ПП. Можна змінити, відредагувавши рядок перекладу: discourse_ai.ai_bot.pm_warning" ai_bot_enable_chat_warning: "Відображати попередження, коли починається чат ПП. Можна змінити, відредагувавши рядок перекладу: discourse_ai.ai_bot.pm_warning"
@ -216,7 +216,7 @@ uk:
description: "Максимальна кількість результатів для включення в пошук якщо порожні, будуть використані правила за замовчуванням, а кількість буде масштабовано залежно від моделі, що використовується. Найвище значення 100." description: "Максимальна кількість результатів для включення в пошук якщо порожні, будуть використані правила за замовчуванням, а кількість буде масштабовано залежно від моделі, що використовується. Найвище значення 100."
base_query: base_query:
name: "Базовий пошуковий запит" name: "Базовий пошуковий запит"
description: "Базовий запит для пошуку. Приклад: \"#urgent\" додасть \"#urgent\" до пошукового запиту і знайде лише теми з категорією або тегом \"терміново\"." description: 'Базовий запит для пошуку. Приклад: "#urgent" додасть "#urgent" до пошукового запиту і знайде лише теми з категорією або тегом "терміново".'
tool_summary: tool_summary:
web_browser: "Перегляд веб-сторінок" web_browser: "Перегляд веб-сторінок"
github_search_files: "Пошук файлів на GitHub" github_search_files: "Пошук файлів на GitHub"
@ -285,17 +285,17 @@ uk:
one: "Знайдено %{count} <a href='%{url}'>результат</a> для '%{query}'" one: "Знайдено %{count} <a href='%{url}'>результат</a> для '%{query}'"
few: "Знайдено %{count} <a href='%{url}'>результати</a> для '%{query}'" few: "Знайдено %{count} <a href='%{url}'>результати</a> для '%{query}'"
many: "Знайдено %{count} <a href='%{url}'>результатів</a> для '%{query}'" many: "Знайдено %{count} <a href='%{url}'>результатів</a> для '%{query}'"
other: "Знайдено %{count} <a href='%{url}'>результатів</a> для \"%{query}\"" other: 'Знайдено %{count} <a href=''%{url}''>результатів</a> для "%{query}"'
search_meta_discourse: search_meta_discourse:
one: "Знайдено %{count} <a href='%{url}'>результат</a> для '%{query}'" one: "Знайдено %{count} <a href='%{url}'>результат</a> для '%{query}'"
few: "Знайдено %{count} <a href='%{url}'>результати</a> для '%{query}'" few: "Знайдено %{count} <a href='%{url}'>результати</a> для '%{query}'"
many: "Знайдено %{count} <a href='%{url}'>результатів</a> для '%{query}'" many: "Знайдено %{count} <a href='%{url}'>результатів</a> для '%{query}'"
other: "Знайдено %{count} <a href='%{url}'>результатів</a> для \"%{query}\"" other: 'Знайдено %{count} <a href=''%{url}''>результатів</a> для "%{query}"'
google: google:
one: "Знайдено %{count} <a href='%{url}'>результат</a> для '%{query}'" one: "Знайдено %{count} <a href='%{url}'>результат</a> для '%{query}'"
few: "Знайдено %{count} <a href='%{url}'>результати</a> для '%{query}'" few: "Знайдено %{count} <a href='%{url}'>результати</a> для '%{query}'"
many: "Знайдено %{count} <a href='%{url}'>результатів</a> для '%{query}'" many: "Знайдено %{count} <a href='%{url}'>результатів</a> для '%{query}'"
other: "Знайдено %{count} <a href='%{url}'>результатів</a> для \"%{query}\"" other: 'Знайдено %{count} <a href=''%{url}''>результатів</a> для "%{query}"'
setting_context: "Читання контексту для: %{setting_name}" setting_context: "Читання контексту для: %{setting_name}"
schema: "%{tables}" schema: "%{tables}"
search_settings: search_settings:

View File

@ -364,12 +364,10 @@ discourse_ai:
type: group_list type: group_list
list_type: compact list_type: compact
default: "3|13" # 3: @staff, 13: @trust_level_3 default: "3|13" # 3: @staff, 13: @trust_level_3
ai_summarize_max_hot_topics_gists_per_batch: ai_summary_gists_enabled:
default: 0 default: false
min: 0
max: 1000
hidden: true hidden: true
ai_hot_topic_gists_allowed_groups: ai_summary_gists_allowed_groups:
type: group_list type: group_list
list_type: compact list_type: compact
default: "" default: ""

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
class RenameAiGistBatchSetting < ActiveRecord::Migration[7.0]
def up
execute "UPDATE site_settings SET name = 'ai_summary_gists_allowed_groups' WHERE name = 'ai_hot_topic_gists_allowed_groups'"
end
def down
execute "UPDATE site_settings SET name = 'ai_hot_topic_gists_allowed_groups' WHERE name = 'ai_summary_gists_allowed_groups'"
end
end

View File

@ -23,14 +23,14 @@ module DiscourseAi
def can_see_gists? def can_see_gists?
return false if !SiteSetting.ai_summarization_enabled return false if !SiteSetting.ai_summarization_enabled
return false if SiteSetting.ai_summarize_max_hot_topics_gists_per_batch.zero? return false if !SiteSetting.ai_summary_gists_enabled
if SiteSetting.ai_hot_topic_gists_allowed_groups.to_s == Group::AUTO_GROUPS[:everyone].to_s if SiteSetting.ai_summary_gists_allowed_groups.to_s == Group::AUTO_GROUPS[:everyone].to_s
return true return true
end end
return false if anonymous? return false if anonymous?
return false if SiteSetting.ai_hot_topic_gists_allowed_groups_map.empty? return false if SiteSetting.ai_summary_gists_allowed_groups_map.empty?
SiteSetting.ai_hot_topic_gists_allowed_groups_map.any? do |group_id| SiteSetting.ai_summary_gists_allowed_groups_map.any? do |group_id|
user.group_ids.include?(group_id) user.group_ids.include?(group_id)
end end
end end

View File

@ -19,7 +19,7 @@ module DiscourseAi
plugin.register_modifier(:topic_query_create_list_topics) do |topics, options| plugin.register_modifier(:topic_query_create_list_topics) do |topics, options|
if Discourse.filters.include?(options[:filter]) && SiteSetting.ai_summarization_enabled && if Discourse.filters.include?(options[:filter]) && SiteSetting.ai_summarization_enabled &&
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch > 0 SiteSetting.ai_summary_gists_enabled
topics.includes(:ai_gist_summary) topics.includes(:ai_gist_summary)
else else
topics topics
@ -35,20 +35,12 @@ module DiscourseAi
object.ai_gist_summary&.summarized_text object.ai_gist_summary&.summarized_text
end end
# To make sure hot topic gists are inmediately up to date, we rely on this event
# instead of using a scheduled job.
plugin.on(:topic_hot_scores_updated) { Jobs.enqueue(:hot_topics_gist_batch) }
# As this event can be triggered quite often, let's be overly cautious enqueueing # As this event can be triggered quite often, let's be overly cautious enqueueing
# jobs if the feature is disabled. # jobs if the feature is disabled.
plugin.on(:post_created) do |post| plugin.on(:post_created) do |post|
if SiteSetting.discourse_ai_enabled && SiteSetting.ai_summarization_enabled && if SiteSetting.discourse_ai_enabled && SiteSetting.ai_summarization_enabled &&
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch > 0 && post.topic SiteSetting.ai_summary_gists_enabled && post.topic
hot_score = TopicHotScore.find_by(topic: post.topic) Jobs.enqueue(:fast_track_topic_gist, topic_id: post&.topic_id)
if hot_score.present? && hot_score.updated_at > 1.day.ago
Jobs.enqueue(:update_hot_topic_gist, topic_id: post&.topic_id)
end
end end
end end
end end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
RSpec.describe Jobs::UpdateHotTopicGist do RSpec.describe Jobs::FastTrackTopicGist do
describe "#execute" do describe "#execute" do
fab!(:topic_1) { Fabricate(:topic) } fab!(:topic_1) { Fabricate(:topic) }
fab!(:post_1) { Fabricate(:post, topic: topic_1, post_number: 1) } fab!(:post_1) { Fabricate(:post, topic: topic_1, post_number: 1) }
@ -9,11 +9,10 @@ RSpec.describe Jobs::UpdateHotTopicGist do
before do before do
assign_fake_provider_to(:ai_summarization_model) assign_fake_provider_to(:ai_summarization_model)
SiteSetting.ai_summarization_enabled = true SiteSetting.ai_summarization_enabled = true
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch = 100 SiteSetting.ai_summary_gists_enabled = true
end end
context "when the hot topic has a gist" do context "when the topic has a gist" do
before { TopicHotScore.create!(topic_id: topic_1.id, score: 0.1) }
fab!(:ai_gist) do fab!(:ai_gist) do
Fabricate(:topic_ai_gist, target: topic_1, original_content_sha: AiSummary.build_sha("12")) Fabricate(:topic_ai_gist, target: topic_1, original_content_sha: AiSummary.build_sha("12"))
end end
@ -48,22 +47,22 @@ RSpec.describe Jobs::UpdateHotTopicGist do
end end
context "when the topic doesn't have a hot topic score" do context "when the topic doesn't have a hot topic score" do
it "does nothing" do it "creates gist" do
subject.execute({}) subject.execute(topic_id: topic_1.id)
gist = AiSummary.gist.find_by(target: topic_1) gist = AiSummary.gist.find_by(target: topic_1)
expect(gist).to be_nil expect(gist).to be_present
end end
end end
context "when the topic has a hot topic score but no gist" do context "when the topic has a hot topic score but no gist" do
before { TopicHotScore.create!(topic_id: topic_1.id, score: 0.1) } before { TopicHotScore.create!(topic_id: topic_1.id, score: 0.1) }
it "does nothing" do it "creates gist" do
subject.execute({}) subject.execute(topic_id: topic_1.id)
gist = AiSummary.gist.find_by(target: topic_1) gist = AiSummary.gist.find_by(target: topic_1)
expect(gist).to be_nil expect(gist).to be_present
end end
end end
end end

View File

@ -1,126 +0,0 @@
# frozen_string_literal: true
RSpec.describe Jobs::HotTopicsGistBatch do
fab!(:topic_1) { Fabricate(:topic) }
fab!(:post_1) { Fabricate(:post, topic: topic_1, post_number: 1) }
fab!(:post_2) { Fabricate(:post, topic: topic_1, post_number: 2) }
before do
assign_fake_provider_to(:ai_summarization_model)
SiteSetting.ai_summarization_enabled = true
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch = 100
end
describe "#execute" do
context "when there is a topic with a hot score" do
before { TopicHotScore.create!(topic_id: topic_1.id, score: 0.1) }
it "does nothing if the plugin is disabled" do
SiteSetting.discourse_ai_enabled = false
subject.execute({})
gist = AiSummary.gist.find_by(target: topic_1)
expect(gist).to be_nil
end
it "does nothing if the summarization module is disabled" do
SiteSetting.ai_summarization_enabled = false
subject.execute({})
gist = AiSummary.gist.find_by(target: topic_1)
expect(gist).to be_nil
end
it "does nothing if hot topics summarization is disabled" do
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch = 0
subject.execute({})
gist = AiSummary.gist.find_by(target: topic_1)
expect(gist).to be_nil
end
it "creates a gist" do
gist_result = "I'm a gist"
DiscourseAi::Completions::Llm.with_prepared_responses([gist_result]) { subject.execute({}) }
gist = AiSummary.gist.find_by(target: topic_1)
expect(gist.summarized_text).to eq(gist_result)
end
context "when we already generated a gist of it" do
fab!(:ai_gist) do
Fabricate(
:topic_ai_gist,
target: topic_1,
original_content_sha: AiSummary.build_sha("12"),
)
end
it "does nothing if the gist is up to date" do
updated_gist = "They updated me :("
DiscourseAi::Completions::Llm.with_prepared_responses([updated_gist]) do
subject.execute({})
end
gist = AiSummary.gist.find_by(target: topic_1)
expect(AiSummary.gist.where(target: topic_1).count).to eq(1)
expect(gist.summarized_text).not_to eq(updated_gist)
expect(gist.original_content_sha).to eq(ai_gist.original_content_sha)
end
it "regenerates it if it's outdated" do
Fabricate(:post, topic: topic_1, post_number: 3)
gist_result = "They updated me"
DiscourseAi::Completions::Llm.with_prepared_responses([gist_result]) do
subject.execute({})
end
gist = AiSummary.gist.find_by(target: topic_1)
expect(gist.summarized_text).to eq(gist_result)
expect(gist.original_content_sha).to eq(AiSummary.build_sha("123"))
end
end
end
context "when there is a topic but it doesn't have a hot score" do
it "does nothing" do
subject.execute({})
gist = AiSummary.gist.find_by(target: topic_1)
expect(gist).to be_nil
end
end
context "when there are multiple hot topics" do
fab!(:topic_2) { Fabricate(:topic) }
fab!(:post_2_1) { Fabricate(:post, topic: topic_2, post_number: 1) }
fab!(:post_2_2) { Fabricate(:post, topic: topic_2, post_number: 2) }
before do
TopicHotScore.create!(topic_id: topic_1.id, score: 0.2)
TopicHotScore.create!(topic_id: topic_2.id, score: 0.4)
end
it "processes them by score order" do
topic_1_gist = "I'm gist of topic 1"
topic_2_gist = "I'm gist of topic 2"
DiscourseAi::Completions::Llm.with_prepared_responses([topic_2_gist, topic_1_gist]) do
subject.execute({})
end
gist = AiSummary.gist.find_by(target: topic_1)
expect(gist.summarized_text).to eq(topic_1_gist)
gist_2 = AiSummary.gist.find_by(target: topic_2)
expect(gist_2.summarized_text).to eq(topic_2_gist)
end
end
end
end

View File

@ -9,6 +9,7 @@ RSpec.describe Jobs::SummariesBackfill do
assign_fake_provider_to(:ai_summarization_model) assign_fake_provider_to(:ai_summarization_model)
SiteSetting.ai_summarization_enabled = true SiteSetting.ai_summarization_enabled = true
SiteSetting.ai_summary_backfill_maximum_topics_per_hour = limit SiteSetting.ai_summary_backfill_maximum_topics_per_hour = limit
SiteSetting.ai_summary_gists_enabled = true
end end
describe "#current_budget" do describe "#current_budget" do

View File

@ -9,7 +9,7 @@ describe DiscourseAi::GuardianExtensions do
group.add(user) group.add(user)
assign_fake_provider_to(:ai_summarization_model) assign_fake_provider_to(:ai_summarization_model)
SiteSetting.ai_summarization_enabled = true SiteSetting.ai_summarization_enabled = true
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch = 1 SiteSetting.ai_summary_gists_enabled = true
end end
let(:anon_guardian) { Guardian.new } let(:anon_guardian) { Guardian.new }
@ -80,7 +80,7 @@ describe DiscourseAi::GuardianExtensions do
end end
describe "#can_see_gists?" do describe "#can_see_gists?" do
before { SiteSetting.ai_hot_topic_gists_allowed_groups = group.id } before { SiteSetting.ai_summary_gists_allowed_groups = group.id }
let(:guardian) { Guardian.new(user) } let(:guardian) { Guardian.new(user) }
context "when there is no user" do context "when there is no user" do
@ -90,7 +90,7 @@ describe DiscourseAi::GuardianExtensions do
end end
context "when setting is set to everyone" do context "when setting is set to everyone" do
before { SiteSetting.ai_hot_topic_gists_allowed_groups = Group::AUTO_GROUPS[:everyone] } before { SiteSetting.ai_summary_gists_allowed_groups = Group::AUTO_GROUPS[:everyone] }
it "returns true" do it "returns true" do
expect(guardian.can_see_gists?).to eq(true) expect(guardian.can_see_gists?).to eq(true)
@ -98,7 +98,7 @@ describe DiscourseAi::GuardianExtensions do
end end
context "when there is a user but it's not a member of the allowed groups" do context "when there is a user but it's not a member of the allowed groups" do
before { SiteSetting.ai_hot_topic_gists_allowed_groups = "" } before { SiteSetting.ai_summary_gists_allowed_groups = "" }
it "returns false" do it "returns false" do
expect(guardian.can_see_gists?).to eq(false) expect(guardian.can_see_gists?).to eq(false)

View File

@ -4,7 +4,7 @@ RSpec.describe DiscourseAi::Summarization::EntryPoint do
before do before do
assign_fake_provider_to(:ai_summarization_model) assign_fake_provider_to(:ai_summarization_model)
SiteSetting.ai_summarization_enabled = true SiteSetting.ai_summarization_enabled = true
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch = 100 SiteSetting.ai_summary_gists_enabled = true
end end
fab!(:user) fab!(:user)
@ -62,8 +62,8 @@ RSpec.describe DiscourseAi::Summarization::EntryPoint do
before do before do
group.add(user) group.add(user)
SiteSetting.ai_hot_topic_gists_allowed_groups = group.id SiteSetting.ai_summary_gists_allowed_groups = group.id
SiteSetting.ai_summarize_max_hot_topics_gists_per_batch = 100 SiteSetting.ai_summary_gists_enabled = true
end end
it "includes the summary" do it "includes the summary" do
@ -81,7 +81,7 @@ RSpec.describe DiscourseAi::Summarization::EntryPoint do
end end
it "doesn't include the summary when the user is not a member of the opt-in group" do it "doesn't include the summary when the user is not a member of the opt-in group" do
SiteSetting.ai_hot_topic_gists_allowed_groups = "" SiteSetting.ai_summary_gists_allowed_groups = ""
gist_topic = topic_query.list_hot.topics.find { |t| t.id == topic_ai_gist.target_id } gist_topic = topic_query.list_hot.topics.find { |t| t.id == topic_ai_gist.target_id }
@ -153,13 +153,4 @@ RSpec.describe DiscourseAi::Summarization::EntryPoint do
end end
end end
end end
describe "#on topic_hot_scores_updated" do
it "queues a job to generate gists" do
expect { DiscourseEvent.trigger(:topic_hot_scores_updated) }.to change(
Jobs::HotTopicsGistBatch.jobs,
:size,
).by(1)
end
end
end end