Add support for search_articles

This commit is contained in:
Pranav
2025-05-11 11:10:03 -07:00
parent 115ca2feb0
commit 2553888a8b
6 changed files with 130 additions and 8 deletions
+1
View File
@@ -33,6 +33,7 @@
#
class Article < ApplicationRecord
include PgSearch::Model
include LlmFormattable
has_many :associated_articles,
class_name: :Article,
@@ -0,0 +1,22 @@
class LlmFormatter::ArticleLlmFormatter
attr_reader :article
def initialize(article)
@article = article
end
def format(*)
<<~TEXT
Title: #{article.title}
ID: #{article.id}
Status: #{article.status}
Category: #{article.category&.name || 'Uncategorized'}
Author: #{article.author&.name}
Views: #{article.views}
Created At: #{article.created_at}
Updated At: #{article.updated_at}
Content:
#{article.content}
TEXT
end
end
@@ -21,10 +21,12 @@ class Captain::Copilot::ChatService < Llm::BaseOpenAiService
end
def register_tools
@tool_registry.register_tool(Captain::Tools::Copilot::GetConversationService)
@tool_registry.register_tool(Captain::Tools::Copilot::SearchConversationService)
@tool_registry.register_tool(Captain::Tools::Copilot::GetArticleService)
@tool_registry.register_tool(Captain::Tools::Copilot::GetContactService)
@tool_registry.register_tool(Captain::Tools::Copilot::GetConversationService)
@tool_registry.register_tool(Captain::Tools::Copilot::SearchArticleService)
@tool_registry.register_tool(Captain::Tools::Copilot::SearchContactService)
@tool_registry.register_tool(Captain::Tools::Copilot::SearchConversationService)
end
def build_initial_messages(config)
@@ -0,0 +1,40 @@
class Captain::Tools::Copilot::GetArticleService < Captain::Tools::BaseService
def name
'get_article'
end
def description
'Get details of an article including its content and metadata'
end
def parameters
{
type: 'object',
properties: {
article_id: {
type: 'number',
description: 'The ID of the article to retrieve'
},
account_id: {
type: 'number',
description: 'The ID of the account the article belongs to'
}
},
required: %w[article_id account_id]
}
end
def execute(arguments)
article_id = arguments['article_id']
account_id = arguments['account_id']
Rails.logger.info { "[CAPTAIN][GetArticle] #{article_id}, #{account_id}" }
return 'Missing required parameters' if article_id.blank? || account_id.blank?
article = Article.find_by(id: article_id, account_id: account_id)
return 'Article not found' if article.nil?
article.to_llm_text
end
end
@@ -0,0 +1,60 @@
class Captain::Tools::Copilot::SearchArticleService < Captain::Tools::BaseService
def name
'search_article'
end
def description
'Search for articles based on query parameters'
end
def parameters
{
type: 'object',
properties: {
account_id: {
type: 'number',
description: 'The ID of the account to search articles in'
},
query: {
type: 'string',
description: 'Search articles by title or content (partial match)'
},
category_id: {
type: 'number',
description: 'Filter articles by category ID'
},
status: {
type: 'string',
enum: %w[draft published archived],
description: 'Filter articles by status'
}
},
required: %w[account_id]
}
end
def execute(arguments)
account_id = arguments['account_id']
query = arguments['query']
category_id = arguments['category_id']
status = arguments['status']
Rails.logger.info do
"[CAPTAIN][SearchArticle] account_id: #{account_id}, query: #{query}, category_id: #{category_id}, status: #{status}"
end
return 'Missing required parameters' if account_id.blank?
articles = Article.where(account_id: account_id)
articles = articles.where('title ILIKE :query OR content ILIKE :query', query: "%#{query}%") if query.present?
articles = articles.where(category_id: category_id) if category_id.present?
articles = articles.where(status: status) if status.present?
return 'No articles found' unless articles.exists?
<<~RESPONSE
Total number of articles: #{articles.count}
#{articles.map(&:to_llm_text).join("\n---\n")}
RESPONSE
end
end
@@ -47,17 +47,14 @@ class Captain::Tools::Copilot::SearchContactService < Captain::Tools::BaseServic
contacts = Contact.where(account_id: account_id)
contacts = contacts.where(email: email) if email.present?
contacts = contacts.where(phone_number: phone_number) if phone_number.present?
contacts = contacts.where('name ILIKE ?', "%#{name}%") if name.present?
contacts = contacts.where('LOWER(name) ILIKE ?', "%#{name.downcase}%") if name.present?
return 'No contacts found' unless contacts.exists?
<<~RESPONSE
Total number of contacts: #{contacts.count}
#{
contacts.map do |contact|
contact.to_llm_text
end.join("\n---\n")
}
#{contacts.map(&:to_llm_text).join("\n---\n")}
RESPONSE
end
end