chromable 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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