chroma-db 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +13 -1
- data/lib/chroma/api_operations/request.rb +125 -0
- data/lib/chroma/chroma.rb +29 -0
- data/lib/chroma/chroma_configuration.rb +75 -0
- data/lib/chroma/errors.rb +71 -0
- data/lib/chroma/resources/collection.rb +384 -0
- data/lib/chroma/resources/database.rb +69 -0
- data/lib/chroma/resources/embedding.rb +23 -0
- data/lib/chroma/util.rb +70 -0
- data/lib/chroma/version.rb +1 -1
- data/lib/chroma-db.rb +18 -0
- data/notebook/Chroma Gem.ipynb +851 -0
- data/notebook/ruby.txt +58 -0
- metadata +13 -3
- data/lib/chroma.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9273343cf2f29991d61d8e5393dfd06541211c84e03769162fa984c9ca2c8620
|
4
|
+
data.tar.gz: 3dd3e94d5914e5776aef673f18b06bbb6f61254bbe4eb51ae25f8675f6c9c72b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c94d838879f22cae956b9a4b7e66f8b8a8d76792770dda6eb9a91b197aa0eb3b8408256653402feb750732f35fb221ae2ebedfe05ab49d89896b80579228ed0
|
7
|
+
data.tar.gz: f5ad7421b54da9909a3a1c76d36d07738ccd44aaa934a7e960e5b102608e24c61e36243b59c0d2ba469e01c34b2cc360e2a07a82516d1a4a2d73cfffa49334fa
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
chroma-db (0.
|
4
|
+
chroma-db (0.2.0)
|
5
5
|
dry-monads (~> 1.6)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
+
addressable (2.8.4)
|
11
|
+
public_suffix (>= 2.0.2, < 6.0)
|
10
12
|
ast (2.4.2)
|
11
13
|
concurrent-ruby (1.2.2)
|
14
|
+
crack (0.4.5)
|
15
|
+
rexml
|
12
16
|
dry-core (1.0.0)
|
13
17
|
concurrent-ruby (~> 1.0)
|
14
18
|
zeitwerk (~> 2.6)
|
@@ -16,6 +20,7 @@ GEM
|
|
16
20
|
concurrent-ruby (~> 1.0)
|
17
21
|
dry-core (~> 1.0, < 2)
|
18
22
|
zeitwerk (~> 2.6)
|
23
|
+
hashdiff (1.0.1)
|
19
24
|
json (2.6.3)
|
20
25
|
language_server-protocol (3.17.0.3)
|
21
26
|
lint_roller (1.0.0)
|
@@ -23,6 +28,7 @@ GEM
|
|
23
28
|
parallel (1.23.0)
|
24
29
|
parser (3.2.2.1)
|
25
30
|
ast (~> 2.4.1)
|
31
|
+
public_suffix (5.0.1)
|
26
32
|
rainbow (3.1.1)
|
27
33
|
rake (13.0.6)
|
28
34
|
rbs (3.1.0)
|
@@ -56,10 +62,15 @@ GEM
|
|
56
62
|
lint_roller (~> 1.0)
|
57
63
|
rubocop-performance (~> 1.16.0)
|
58
64
|
unicode-display_width (2.4.2)
|
65
|
+
webmock (3.18.1)
|
66
|
+
addressable (>= 2.8.0)
|
67
|
+
crack (>= 0.3.2)
|
68
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
59
69
|
zeitwerk (2.6.8)
|
60
70
|
|
61
71
|
PLATFORMS
|
62
72
|
arm64-darwin-22
|
73
|
+
x86_64-linux
|
63
74
|
|
64
75
|
DEPENDENCIES
|
65
76
|
chroma-db!
|
@@ -67,6 +78,7 @@ DEPENDENCIES
|
|
67
78
|
rake (~> 13.0)
|
68
79
|
rbs (~> 3.1)
|
69
80
|
standard (~> 1.3)
|
81
|
+
webmock (~> 3.18, >= 3.18.1)
|
70
82
|
|
71
83
|
BUNDLED WITH
|
72
84
|
2.4.12
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Chroma
|
4
|
+
module APIOperations
|
5
|
+
# Request's response Data object.
|
6
|
+
#
|
7
|
+
# status - HTTP status code. It is zero when a request fails due to network error.
|
8
|
+
# body - Parsed JSON object or response body.
|
9
|
+
# headers - HTTP response headers.
|
10
|
+
# error - Exception or Net::HTTPResponse object if the response is not Net::HTTPSuccess
|
11
|
+
Response = Data.define(:status, :body, :headers, :error)
|
12
|
+
|
13
|
+
# Request module provides functionality to perform HTTP requests.
|
14
|
+
module Request
|
15
|
+
module ClassMethods
|
16
|
+
include Dry::Monads[:result]
|
17
|
+
|
18
|
+
# Execute an HTTP request and return a monad wrapping the response.
|
19
|
+
#
|
20
|
+
# method - The HTTP method to use (e.g. 'GET', 'POST'). Method must be a `Symbol`.
|
21
|
+
# url - The URL to send the request to.
|
22
|
+
# params - The query parameters or request body. Params needs to be in a form of a Hash.
|
23
|
+
# options - Additional options to pass to the request.
|
24
|
+
#
|
25
|
+
# A `Dry::Monads::Result` monad wrapping the response, either a success or failure.
|
26
|
+
# The response is a `Chroma::APIOperations::Response` Data object.
|
27
|
+
#
|
28
|
+
# Examples
|
29
|
+
#
|
30
|
+
# result = execute_request(:get, "https://example.com", {name: "test request"})
|
31
|
+
# if result.success?
|
32
|
+
# puts "Response status: #{result.success.status}"
|
33
|
+
# puts "Response body: #{result.success.body}"
|
34
|
+
# else
|
35
|
+
# puts "Request failed with error: #{result.failure.error}"
|
36
|
+
# end
|
37
|
+
def execute_request(method, url, params = {}, options = {})
|
38
|
+
uri = URI.parse(url)
|
39
|
+
|
40
|
+
request = build_request(method, uri, params)
|
41
|
+
|
42
|
+
use_ssl = options.delete(:use_ssl) || false
|
43
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl:) do |http|
|
44
|
+
Chroma::Util.log_debug("Sending a request", {method:, uri:, params:})
|
45
|
+
http.request(request)
|
46
|
+
end
|
47
|
+
|
48
|
+
build_response(response)
|
49
|
+
rescue => ex
|
50
|
+
build_response(ex)
|
51
|
+
end
|
52
|
+
|
53
|
+
private def build_response(response)
|
54
|
+
case response
|
55
|
+
in Net::HTTPSuccess => success_response
|
56
|
+
Chroma::Util.log_info("Successful response", code: success_response.code)
|
57
|
+
|
58
|
+
build_response_details(success_response)
|
59
|
+
in Net::HTTPRedirection => redirect_response
|
60
|
+
Chroma::Util.log_info("Server redirect response", code: redirect_response.code, location: redirect_response["location"])
|
61
|
+
|
62
|
+
build_response_details(redirect_response)
|
63
|
+
in Net::HTTPClientError => client_error_response
|
64
|
+
Chroma::Util.log_error("Client error response", code: client_error_response.code, body: client_error_response.body)
|
65
|
+
|
66
|
+
build_response_details(client_error_response)
|
67
|
+
in Net::HTTPServerError => server_error_response
|
68
|
+
Chroma::Util.log_error("Server error response", code: server_error_response.code)
|
69
|
+
|
70
|
+
build_response_details(server_error_response, parse_body: false)
|
71
|
+
else
|
72
|
+
Chroma::Util.log_error("An error happened", error: response.to_s)
|
73
|
+
|
74
|
+
build_response_details(response, exception: true, parse_body: false)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private def build_response_details(response, exception: false, parse_body: true)
|
79
|
+
response_data = Chroma::APIOperations::Response.new(
|
80
|
+
status: exception ? 0 : response.code.to_i,
|
81
|
+
body: if exception
|
82
|
+
exception.to_s
|
83
|
+
else
|
84
|
+
(parse_body ? body_to_json(response.body) : response.body)
|
85
|
+
end,
|
86
|
+
headers: exception ? {} : response.each_header.to_h,
|
87
|
+
error: response.is_a?(Net::HTTPSuccess) ? nil : response
|
88
|
+
)
|
89
|
+
|
90
|
+
case response
|
91
|
+
in Net::HTTPSuccess
|
92
|
+
return Success(response_data)
|
93
|
+
else
|
94
|
+
return Failure(response_data)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private def body_to_json(content)
|
99
|
+
JSON.parse(content, symbolize_keys: true)
|
100
|
+
rescue JSON::ParserError, TypeError
|
101
|
+
content
|
102
|
+
end
|
103
|
+
|
104
|
+
private def build_request(method, uri, params)
|
105
|
+
request = case method
|
106
|
+
when :post then Net::HTTP::Post.new(uri)
|
107
|
+
when :put then Net::HTTP::Put.new(uri)
|
108
|
+
when :delete then Net::HTTP::Delete.new(uri)
|
109
|
+
else
|
110
|
+
Net::HTTP::Get.new(uri)
|
111
|
+
end
|
112
|
+
|
113
|
+
request.content_type = "application/json"
|
114
|
+
request.body = params.to_json if params.size > 0
|
115
|
+
|
116
|
+
request
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.included(base)
|
121
|
+
base.extend(ClassMethods)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Chroma
|
4
|
+
# map to the same values as the standard library's logger
|
5
|
+
LEVEL_DEBUG = Logger::DEBUG
|
6
|
+
LEVEL_ERROR = Logger::ERROR
|
7
|
+
LEVEL_INFO = Logger::INFO
|
8
|
+
|
9
|
+
@config = Chroma::ChromaConfiguration.setup
|
10
|
+
|
11
|
+
class << self
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
attr_reader :config
|
15
|
+
|
16
|
+
# User configuration options
|
17
|
+
def_delegators :@config, :connect_host, :connect_host=
|
18
|
+
def_delegators :@config, :api_base, :api_base=
|
19
|
+
def_delegators :@config, :api_version, :api_version=
|
20
|
+
def_delegators :@config, :log_level, :log_level=
|
21
|
+
def_delegators :@config, :logger, :logger=
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.api_url
|
25
|
+
"#{connect_host}/#{api_base}/#{api_version}"
|
26
|
+
end
|
27
|
+
|
28
|
+
Chroma.log_level = ENV["CHROMA_LOG"].to_i unless ENV["CHROMA_LOG"].nil?
|
29
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Chroma
|
4
|
+
# The ChromaConfiguration class allows you to configure the connection settings for a Chroma service client.
|
5
|
+
# It can be initialized directly calling #new method.
|
6
|
+
#
|
7
|
+
# Examples
|
8
|
+
#
|
9
|
+
# configuration = Chroma::ChromaConfiguration.new
|
10
|
+
# configurarion.connect_host = "https://chroma.example.com"
|
11
|
+
#
|
12
|
+
# Or via a setup block.
|
13
|
+
#
|
14
|
+
# Examples
|
15
|
+
#
|
16
|
+
# Chroma::ChromaConfiguration.setup do |config|
|
17
|
+
# config.connect_host = "https://chroma.example.com"
|
18
|
+
# end
|
19
|
+
class ChromaConfiguration
|
20
|
+
# Sets the host name for the Chroma service.
|
21
|
+
#
|
22
|
+
# Examples
|
23
|
+
#
|
24
|
+
# config.connect_host = "chroma.example.com"
|
25
|
+
#
|
26
|
+
# Returns the String host name.
|
27
|
+
attr_accessor :connect_host
|
28
|
+
|
29
|
+
# Sets the base path for the Chroma API.
|
30
|
+
#
|
31
|
+
# Examples
|
32
|
+
#
|
33
|
+
# config.api_base = "/api"
|
34
|
+
#
|
35
|
+
# Returns the String API base path.
|
36
|
+
attr_accessor :api_base
|
37
|
+
# Sets the version of the Chroma API.
|
38
|
+
#
|
39
|
+
# Examples
|
40
|
+
#
|
41
|
+
# config.api_version = "v1"
|
42
|
+
#
|
43
|
+
# Returns the String API version.
|
44
|
+
attr_accessor :api_version
|
45
|
+
# Sets the logger for the Chroma service client.
|
46
|
+
#
|
47
|
+
# Examples
|
48
|
+
#
|
49
|
+
# config.logger = Logger.new(STDOUT)
|
50
|
+
#
|
51
|
+
# Returns the Logger instance.
|
52
|
+
attr_accessor :logger
|
53
|
+
# Sets the logger's log level for the Chroma service client.
|
54
|
+
#
|
55
|
+
# Examples
|
56
|
+
#
|
57
|
+
# config.log_level = Chroma::LEVEL_INFO
|
58
|
+
#
|
59
|
+
# Returns the log level constant
|
60
|
+
attr_accessor :log_level
|
61
|
+
|
62
|
+
def self.setup
|
63
|
+
new.tap do |instance|
|
64
|
+
yield(instance) if block_given?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def initialize
|
69
|
+
@api_base = "api"
|
70
|
+
@api_version = "v1"
|
71
|
+
|
72
|
+
@log_level = Chroma::LEVEL_INFO
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Chroma
|
4
|
+
# ChromaError is the base error from which all other more specific Chrome
|
5
|
+
# errors derive.
|
6
|
+
class ChromaError < StandardError
|
7
|
+
attr_accessor :response
|
8
|
+
|
9
|
+
attr_reader :message
|
10
|
+
attr_reader :error
|
11
|
+
attr_reader :body
|
12
|
+
attr_reader :status
|
13
|
+
|
14
|
+
def initialize(message = nil, status: nil, body: nil, response: nil)
|
15
|
+
@message = message
|
16
|
+
@status = status
|
17
|
+
@body = body
|
18
|
+
@response = response
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
status_value = @status.nil? ? "" : "(Status #{@status}) "
|
23
|
+
"#{status_value}#{@message}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# APIConnectionError is raised in the event that the SDK can't connect to
|
28
|
+
# Chroma's database. That can be for a variety of different reasons from a
|
29
|
+
# downed network to a bad TLS certificate.
|
30
|
+
class APIConnectionError < ChromaError
|
31
|
+
end
|
32
|
+
|
33
|
+
# InvalidRequestError is raised when a request is initiated with invalid
|
34
|
+
# parameters.
|
35
|
+
class InvalidRequestError < ChromaError
|
36
|
+
def initialize(message = nil, status: nil, body: nil, response: nil)
|
37
|
+
super
|
38
|
+
|
39
|
+
decode_message
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def decode_message
|
45
|
+
if message.include?("ValueError")
|
46
|
+
error = JSON.parse(message)
|
47
|
+
value = error.fetch("error", "").sub("ValueError('", "").sub("')", "")
|
48
|
+
@message = value if !value.nil?
|
49
|
+
end
|
50
|
+
rescue JSON::ParserError, TypeError
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# APIError is a generic error that may be raised in cases where none of the
|
55
|
+
# other named errors cover the problem.
|
56
|
+
class APIError < ChromaError
|
57
|
+
def initialize(message = nil, status: nil, body: nil, response: nil)
|
58
|
+
super
|
59
|
+
|
60
|
+
decode_message
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def decode_message
|
66
|
+
if message.is_a?(Hash) && message.has_key?("error")
|
67
|
+
@message = message.fetch("error")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|