This PR introduces a review step for generated FAQs, allowing a human to validate and approve them before use in customer interactions. While hallucinations are minimal, this step ensures accurate and reliable FAQs for Captain to use during LLM calls when responding to customers. - Added a status field for the FAQ - Allow the filter on the UI. <img width="1072" alt="Screenshot 2025-01-15 at 6 39 26 PM" src="https://github.com/user-attachments/assets/81dfc038-31e9-40e6-8a09-586ebc4e8384" />
67 lines
2.1 KiB
Ruby
67 lines
2.1 KiB
Ruby
# == Schema Information
|
|
#
|
|
# Table name: captain_assistant_responses
|
|
#
|
|
# id :bigint not null, primary key
|
|
# answer :text not null
|
|
# embedding :vector(1536)
|
|
# question :string not null
|
|
# status :integer default("approved"), not null
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# account_id :bigint not null
|
|
# assistant_id :bigint not null
|
|
# document_id :bigint
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_captain_assistant_responses_on_account_id (account_id)
|
|
# index_captain_assistant_responses_on_assistant_id (assistant_id)
|
|
# index_captain_assistant_responses_on_document_id (document_id)
|
|
# index_captain_assistant_responses_on_status (status)
|
|
# vector_idx_knowledge_entries_embedding (embedding) USING ivfflat
|
|
#
|
|
class Captain::AssistantResponse < ApplicationRecord
|
|
self.table_name = 'captain_assistant_responses'
|
|
|
|
belongs_to :assistant, class_name: 'Captain::Assistant'
|
|
belongs_to :account
|
|
belongs_to :document, optional: true, class_name: 'Captain::Document'
|
|
has_neighbors :embedding, normalize: true
|
|
|
|
validates :question, presence: true
|
|
validates :answer, presence: true
|
|
|
|
before_validation :ensure_account
|
|
before_validation :ensure_status
|
|
after_commit :update_response_embedding
|
|
|
|
scope :ordered, -> { order(created_at: :desc) }
|
|
scope :by_account, ->(account_id) { where(account_id: account_id) }
|
|
scope :by_assistant, ->(assistant_id) { where(assistant_id: assistant_id) }
|
|
scope :with_document, ->(document_id) { where(document_id: document_id) }
|
|
|
|
enum status: { pending: 0, approved: 1 }
|
|
|
|
def self.search(query)
|
|
embedding = Captain::Llm::EmbeddingService.new.get_embedding(query)
|
|
nearest_neighbors(:embedding, embedding, distance: 'cosine').limit(5)
|
|
end
|
|
|
|
private
|
|
|
|
def ensure_status
|
|
self.status ||= :approved
|
|
end
|
|
|
|
def ensure_account
|
|
self.account = assistant&.account
|
|
end
|
|
|
|
def update_response_embedding
|
|
return unless saved_change_to_question? || saved_change_to_answer? || embedding.nil?
|
|
|
|
Captain::Llm::UpdateEmbeddingJob.perform_later(self, "#{question}: #{answer}")
|
|
end
|
|
end
|