chromable 0.1.4 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b0b02fff83da824d9195113352c1d68dfaaa06bde568eba6448fb4cb79e0919
4
- data.tar.gz: 879ac8e61ba6be8a9490174f13517c509409c0d271fd93e9fd06d6a22cf3f1fe
3
+ metadata.gz: d44fa49957eefd26d00d3fb2315b51f928bd6ecdac7cdc4f849537cac23f036b
4
+ data.tar.gz: ab51d49d9b558e6d6ba936640026af66258567c0750f2ce11c7b6e01a0b8fea1
5
5
  SHA512:
6
- metadata.gz: a5a97a3c29f46ee311eafa1d2ea9d51d032568a2bafa64877d22590403152b623318a93d650328af3db1db005e5315b4a90002185a9bfa0c328fcb81dd374276
7
- data.tar.gz: cc14d192452c5e4f72ee090f5423c7b78afe1449e1cd1b25009fcb7d4db29394fe50a2093e107c438f9d4b0d60a46ff8f3230f4a6fd9a1aab5f5b33cdc99798e
6
+ metadata.gz: 2a6be5bd9ec59535eb33a59fc543baa23954ac43c4bc69b8a6e6d19eaab231d313180ba714781f85342f838bfdd4fd70fcfa32c785f663b880128d6a9425a69e
7
+ data.tar.gz: f63ffea813494e3143c16ed900e190d52866fa11348bac39db894c09ad885e66115b0cb8d0e492f2fb18846b29d8fcb76c4dbdbf3c271e3fd4f6afb417350ee9
data/.rubocop.yml CHANGED
@@ -2,7 +2,7 @@ require:
2
2
  - rubocop-rspec
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.6
5
+ TargetRubyVersion: 3.0
6
6
  NewCops: enable
7
7
 
8
8
  Layout/LineLength:
data/README.md CHANGED
@@ -32,8 +32,14 @@ class Post < ApplicationRecord
32
32
 
33
33
  chromable document: :content, metadata: %i[author category], embedder: :embed
34
34
 
35
- def embed
36
- # Call OpenAI now please :)
35
+ def self.embed(text, **options)
36
+ options[:is_query] ||= false
37
+
38
+ if options[:is_query]
39
+ # Call OpenAI API to embed `text` as a search query.
40
+ else
41
+ # Call OpenAI API to embed `text` as a post content.
42
+ end
37
43
  end
38
44
  end
39
45
  ```
@@ -41,22 +47,36 @@ end
41
47
  Where:
42
48
  - `document:` is a callable represents the text content you want to embed and store in ChromaDB.
43
49
  - `metadata:` is the list of attributes to be passed to ChromaDB as metadata to be used to filter.
44
- - `embedder:` is a callable returns the embedding representation for the current instance.
50
+ - `embedder:` is a callable defined in the model that returns the embedding representation for the given `text` and `options`.
45
51
 
46
52
  Optionaly you can pass `collection_name:`. If not passed, the plural form of the model name will be used.
47
53
 
48
- All `chromable` method arguments are optional.
54
+ The only required option for `chromable` method is `document:`.
49
55
 
50
- At this point, `chromable` will create, update, and destroy the ChromaDB embeddings for your objects based on Rails callbacks.
56
+ At this point, `chromable` will create, update, and destroy the ChromaDB embeddings for your objects based on Rails `after_save` and `after_destroy` callbacks.
57
+
58
+ To interact with the ChromaDB collection, `chromable` provides `Model.query` method to query the collection and `Model.collection` method to access the collection directly.
59
+
60
+ ```ruby
61
+ puts Post.collection.count # Gets the number of documents inside the collection. Should always match Post.count.
62
+
63
+ Post.query(
64
+ query: params[:query],
65
+ results: 20,
66
+ where: chroma_search_filters,
67
+ type: 'query' # `type` here will be passed to `Post.embed` as an option.
68
+ )
69
+ ```
70
+
71
+ `Model.query` accepts the same arguments accepted by `chroma-db` gem `query` method. Extra arguments will be passed to the `embedder:`. Behind the scene, `Model.query` will embed the given `query:` text, then query the collection, and return the closest `results:` records.
51
72
 
52
- To interact with the ChromaDB collection, `chromable` provides `Model.collection` method to retrieve the collection instance.
53
73
  Also, `chromable` provides the following methods for each model instance:
54
74
 
55
75
  - `embedding`: Retrieves the instance's ChromaDB embedding object.
56
76
  - `upsert_embedding`: Creates or updates the instance's ChromaDB embedding object.
57
77
  - `destroy_embedding`: Destroys the instance's ChromaDB embedding object.
58
78
 
59
- All these methods (including `Model.collection`) are available with `chroma_` prefix, if you have similar methods defined in your model.
79
+ All these methods (including `Model.query` and `Model.collection`) are available with `chroma_` prefix, if you have similar methods defined in your model.
60
80
 
61
81
  ## Development
62
82
 
data/chromable.gemspec CHANGED
@@ -32,7 +32,6 @@ Gem::Specification.new do |spec|
32
32
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
33
33
  spec.require_paths = ['lib']
34
34
 
35
- spec.add_dependency 'activesupport', '>= 6.1'
36
35
  spec.add_dependency 'chroma-db', '>= 0.6.0'
37
36
 
38
37
  # For more information and examples about making a new gem, check out our
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chromable
4
- VERSION = '0.1.4'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/chromable.rb CHANGED
@@ -1,25 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  require_relative 'chromable/version'
6
4
 
7
5
  # Ruby on Rails integration for ChromaDB.
8
6
  module Chromable
9
- extend ActiveSupport::Concern
10
-
11
- included do
12
- after_save :chroma_upsert_embedding
13
- after_destroy :chroma_destroy_embedding
7
+ def self.included(base)
8
+ base.extend ClassMethods
9
+ base.class_attribute :collection_name
10
+ base.class_attribute :document
11
+ base.class_attribute :metadata
12
+ base.class_attribute :embedder
14
13
 
15
- class_attribute :collection_name
16
- class_attribute :document
17
- class_attribute :metadata
18
- class_attribute :embedder
14
+ base.after_save :chroma_upsert_embedding
15
+ base.after_destroy :chroma_destroy_embedding
19
16
  end
20
17
 
21
- class_methods do
22
- def chromable(collection_name: nil, document: nil, metadata: nil, embedder: nil)
18
+ # Methods to be added to the model class.
19
+ module ClassMethods
20
+ def chromable(document:, metadata: nil, embedder: nil, collection_name: nil)
23
21
  self.collection_name = (collection_name.presence || name.underscore.pluralize)
24
22
  self.document = document
25
23
  self.metadata = metadata
@@ -30,7 +28,25 @@ module Chromable
30
28
  Chroma::Resources::Collection.get_or_create(collection_name)
31
29
  end
32
30
 
33
- alias_method :collection, :chroma_collection unless method_defined? :collection
31
+ def chroma_query( # rubocop:disable Metrics/ParameterLists
32
+ query:,
33
+ results: 10,
34
+ where: {},
35
+ where_document: {},
36
+ include: %w[metadatas documents distances],
37
+ **embedder_options
38
+ )
39
+ find(chroma_collection.query(
40
+ query_embeddings: [send(embedder, query, **embedder_options)],
41
+ results: results,
42
+ where: where,
43
+ where_document: where_document,
44
+ include: include
45
+ ).map(&:id))
46
+ end
47
+
48
+ alias collection chroma_collection unless method_defined? :collection
49
+ alias query chroma_query unless method_defined? :query
34
50
  end
35
51
 
36
52
  def chroma_embedding
@@ -38,14 +54,7 @@ module Chromable
38
54
  end
39
55
 
40
56
  def chroma_upsert_embedding
41
- self.class.chroma_collection.upsert(
42
- Chroma::Resources::Embedding.new(
43
- id: id,
44
- document: self.class.document ? send(self.class.document) : nil,
45
- embedding: self.class.embedder ? send(self.class.embedder) : nil,
46
- metadata: self.class.metadata ? self.class.metadata.index_with { |attribute| send(attribute) } : nil
47
- )
48
- )
57
+ self.class.chroma_collection.upsert(build_embedding)
49
58
  end
50
59
 
51
60
  def chroma_destroy_embedding
@@ -55,4 +64,17 @@ module Chromable
55
64
  alias embedding chroma_embedding unless method_defined? :embedding
56
65
  alias upsert_embedding chroma_upsert_embedding unless method_defined? :upsert_embedding
57
66
  alias destroy_embedding chroma_destroy_embedding unless method_defined? :destroy_embedding
67
+
68
+ private
69
+
70
+ def build_embedding
71
+ document = send(self.class.document)
72
+
73
+ Chroma::Resources::Embedding.new(
74
+ id: id,
75
+ document: document,
76
+ embedding: self.class.embedder && self.class.send(self.class.embedder, document),
77
+ metadata: self.class.metadata&.index_with { |attribute| send(attribute) }
78
+ )
79
+ end
58
80
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chromable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ali Hamdi Ali Fadel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-08 00:00:00.000000000 Z
11
+ date: 2023-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: activesupport
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '6.1'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '6.1'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: chroma-db
29
15
  requirement: !ruby/object:Gem::Requirement