mirror of
https://github.com/we-promise/sure.git
synced 2026-09-08 16:14:23 +00:00
* Add configurable OpenAI request timeout * Address AI timeout review feedback --------- Co-authored-by: Jonathan Kaiser <jaysbeekay@users.noreply.github.com>
91 lines
2.5 KiB
Ruby
91 lines
2.5 KiB
Ruby
# Adapter that delegates to OpenAI's hosted vector-store and file-search APIs.
|
|
#
|
|
# Requirements:
|
|
# - gem "ruby-openai" (already in Gemfile)
|
|
# - OPENAI_ACCESS_TOKEN env var or Setting.openai_access_token
|
|
#
|
|
# OpenAI manages chunking, embedding, and retrieval; we simply upload files
|
|
# and issue search queries.
|
|
class VectorStore::Openai < VectorStore::Base
|
|
# Builds a vector-store client with the same OpenAI request timeout as chat and batch calls.
|
|
def initialize(access_token:, uri_base: nil)
|
|
client_options = { access_token: access_token }
|
|
client_options[:uri_base] = uri_base if uri_base.present?
|
|
client_options[:request_timeout] = Provider::Openai.request_timeout
|
|
|
|
@client = ::OpenAI::Client.new(**client_options)
|
|
end
|
|
|
|
def create_store(name:)
|
|
with_response do
|
|
response = client.vector_stores.create(parameters: { name: name })
|
|
{ id: response["id"] }
|
|
end
|
|
end
|
|
|
|
def delete_store(store_id:)
|
|
with_response do
|
|
client.vector_stores.delete(id: store_id)
|
|
end
|
|
end
|
|
|
|
def upload_file(store_id:, file_content:, filename:)
|
|
with_response do
|
|
tempfile = Tempfile.new([ File.basename(filename, ".*"), File.extname(filename) ])
|
|
begin
|
|
tempfile.binmode
|
|
tempfile.write(file_content)
|
|
tempfile.rewind
|
|
|
|
file_response = client.files.upload(
|
|
parameters: { file: tempfile, purpose: "assistants" }
|
|
)
|
|
file_id = file_response["id"]
|
|
|
|
begin
|
|
client.vector_store_files.create(
|
|
vector_store_id: store_id,
|
|
parameters: { file_id: file_id }
|
|
)
|
|
rescue => e
|
|
client.files.delete(id: file_id) rescue nil
|
|
raise
|
|
end
|
|
|
|
{ file_id: file_id }
|
|
ensure
|
|
tempfile.close
|
|
tempfile.unlink
|
|
end
|
|
end
|
|
end
|
|
|
|
def remove_file(store_id:, file_id:)
|
|
with_response do
|
|
client.vector_store_files.delete(vector_store_id: store_id, id: file_id)
|
|
end
|
|
end
|
|
|
|
def search(store_id:, query:, max_results: 10)
|
|
with_response do
|
|
response = client.vector_stores.search(
|
|
id: store_id,
|
|
parameters: { query: query, max_num_results: max_results }
|
|
)
|
|
|
|
(response["data"] || []).map do |result|
|
|
{
|
|
content: Array(result["content"]).filter_map { |c| c["text"] }.join("\n"),
|
|
filename: result["filename"],
|
|
score: result["score"],
|
|
file_id: result["file_id"]
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :client
|
|
end
|