mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-07-23 22:43:27 +00:00
* DEV: Better strategies for summarization The strategy responsibility needs to be "Given a collection of texts, I know how to summarize them most efficiently, using the minimum amount of requests and maximizing token usage". There are different token limits for each model, so it all boils down to two different strategies: Fold all these texts into a single one, doing the summarization in chunks, and then build a summary from those. Build it by combining texts in a single prompt, and truncate it according to your token limits. While the latter is less than ideal, we need it for "bart-large-cnn-samsum" and "flan-t5-base-samsum", both with low limits. The rest will rely on folding. * Expose summarized chunks to users
85 lines
2.4 KiB
Ruby
85 lines
2.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module DiscourseAi
|
|
module Summarization
|
|
module Models
|
|
class Anthropic < Base
|
|
def display_name
|
|
"Anthropic's #{model}"
|
|
end
|
|
|
|
def correctly_configured?
|
|
SiteSetting.ai_anthropic_api_key.present?
|
|
end
|
|
|
|
def configuration_hint
|
|
I18n.t(
|
|
"discourse_ai.summarization.configuration_hint",
|
|
count: 1,
|
|
setting: "ai_anthropic_api_key",
|
|
)
|
|
end
|
|
|
|
def concatenate_summaries(summaries)
|
|
instructions = <<~TEXT
|
|
Human: Concatenate the following disjoint summaries inside the given input tags, creating a cohesive narrative.
|
|
Include only the summary inside <ai> tags.
|
|
TEXT
|
|
|
|
instructions += summaries.reduce("") { |m, s| m += "<input>#{s}</input>\n" }
|
|
instructions += "Assistant:\n"
|
|
|
|
completion(instructions)
|
|
end
|
|
|
|
def summarize_with_truncation(contents, opts)
|
|
instructions = build_base_prompt(opts)
|
|
|
|
text_to_summarize = contents.map { |c| format_content_item(c) }.join
|
|
truncated_content = tokenizer.truncate(text_to_summarize, max_tokens - reserved_tokens)
|
|
|
|
instructions += "<input>#{truncated_content}</input>\nAssistant:\n"
|
|
|
|
completion(instructions)
|
|
end
|
|
|
|
private
|
|
|
|
def summarize_chunk(chunk_text, opts)
|
|
completion(build_base_prompt(opts) + "<input>#{chunk_text}</input>\nAssistant:\n")
|
|
end
|
|
|
|
def build_base_prompt(opts)
|
|
base_prompt = <<~TEXT
|
|
Human: Summarize the following forum discussion inside the given <input> tag.
|
|
Include only the summary inside <ai> tags.
|
|
TEXT
|
|
|
|
if opts[:resource_path]
|
|
base_prompt += "Try generating links as well the format is #{opts[:resource_path]}.\n"
|
|
end
|
|
|
|
base_prompt += "The discussion title is: #{opts[:content_title]}.\n" if opts[
|
|
:content_title
|
|
]
|
|
|
|
base_prompt += "Don't use more than 400 words.\n"
|
|
end
|
|
|
|
def completion(prompt)
|
|
response =
|
|
::DiscourseAi::Inference::AnthropicCompletions.perform!(prompt, model).dig(:completion)
|
|
|
|
Nokogiri::HTML5.fragment(response).at("ai").text
|
|
end
|
|
|
|
def tokenizer
|
|
DiscourseAi::Tokenizer::AnthropicTokenizer
|
|
end
|
|
|
|
attr_reader :max_tokens
|
|
end
|
|
end
|
|
end
|
|
end
|