chromable 0.2.0 → 0.3.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: d44fa49957eefd26d00d3fb2315b51f928bd6ecdac7cdc4f849537cac23f036b
4
- data.tar.gz: ab51d49d9b558e6d6ba936640026af66258567c0750f2ce11c7b6e01a0b8fea1
3
+ metadata.gz: d33a705c79d42fb0495bb63e4ad7d04e8e3eea823400ea213f362af3e4ce09c8
4
+ data.tar.gz: d18bc615f1a6b22530d76b06b471e07688be422a9af55a92d81419ae48eb4d84
5
5
  SHA512:
6
- metadata.gz: 2a6be5bd9ec59535eb33a59fc543baa23954ac43c4bc69b8a6e6d19eaab231d313180ba714781f85342f838bfdd4fd70fcfa32c785f663b880128d6a9425a69e
7
- data.tar.gz: f63ffea813494e3143c16ed900e190d52866fa11348bac39db894c09ad885e66115b0cb8d0e492f2fb18846b29d8fcb76c4dbdbf3c271e3fd4f6afb417350ee9
6
+ metadata.gz: cfc65982c4f7952170630630eba0c6bf2bdc7708fae70727cb013d1cc1fe2b88b55e2bf08d9e0231864a0790373db2dfb1db95584c8ed328f0131c9e6a4c8d10
7
+ data.tar.gz: 6a0b4a7af862ada818d888ed6ae672a23d85057726df9da40f3c715cd1c80fa71ebfac10e00833dd0cf9908b678d3746d3ead9d9cc6f73fc4ae23436a1e3a13e
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Ruby on Rails integration for ChromaDB based on `chroma-db` gem.
4
4
 
5
+ `chromable` were tested with Ruby 3.2.2 and Rails 7.1.2.
6
+
5
7
  ## Installation
6
8
 
7
9
  Install `chromable` and add it to the application's Gemfile by executing:
@@ -30,7 +32,7 @@ Then, include `Chromable` module in your model and initialize it:
30
32
  class Post < ApplicationRecord
31
33
  include Chromable
32
34
 
33
- chromable document: :content, metadata: %i[author category], embedder: :embed
35
+ chromable document: :content, metadata: %i[author category], embedder: :embed, keep_document: false
34
36
 
35
37
  def self.embed(text, **options)
36
38
  options[:is_query] ||= false
@@ -45,13 +47,14 @@ end
45
47
  ```
46
48
 
47
49
  Where:
48
- - `document:` is a callable represents the text content you want to embed and store in ChromaDB.
49
- - `metadata:` is the list of attributes to be passed to ChromaDB as metadata to be used to filter.
50
- - `embedder:` is a callable defined in the model that returns the embedding representation for the given `text` and `options`.
50
+ - `document:` is a callable represents the text content you want to embed and store in ChromaDB (e.g. Could be a model attribute).
51
+ - `metadata:` is a list of callables to be evaluated and passed to ChromaDB as metadata to be used to filter (e.g. Could be an instance method).
52
+ - `embedder:` is a callable defined at the model level that returns the embedding representation for the given `text` based on some `options`.
53
+ - `keep_document:` tells chromable to pass the `document:` to ChromaDB and save it or not. It is useful if you just want to have the embeddings in ChromaDB and the rest of the data in your Rails application database to reduce memory footprint. `keep_document:` is `true` by default.
51
54
 
52
55
  Optionaly you can pass `collection_name:`. If not passed, the plural form of the model name will be used.
53
56
 
54
- The only required option for `chromable` method is `document:`.
57
+ The only required option for `chromable` is `document:`.
55
58
 
56
59
  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
60
 
@@ -64,11 +67,11 @@ Post.query(
64
67
  query: params[:query],
65
68
  results: 20,
66
69
  where: chroma_search_filters,
67
- type: 'query' # `type` here will be passed to `Post.embed` as an option.
70
+ is_query: true # `is_query` here will be passed to `Post.embed` as an option.
68
71
  )
69
72
  ```
70
73
 
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.
74
+ `Model.query` accepts the same arguments accepted by `chroma-db` gem `query` method. Extra arguments will be passed to the `embedder:` as `options`. Behind the scenes, `Model.query` will embed the given `query:` text, then query the collection, and return the closest `results:` records.
72
75
 
73
76
  Also, `chromable` provides the following methods for each model instance:
74
77
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chromable
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/chromable.rb CHANGED
@@ -6,30 +6,53 @@ require_relative 'chromable/version'
6
6
  module Chromable
7
7
  def self.included(base)
8
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
9
+ base.include InstanceMethods
13
10
 
14
11
  base.after_save :chroma_upsert_embedding
15
12
  base.after_destroy :chroma_destroy_embedding
16
13
  end
17
14
 
15
+ # Chromable settings class to hide them from Rails models.
16
+ class Settings
17
+ attr_accessor :document, :collection_name, :metadata, :embedder, :keep_document
18
+
19
+ def initialize(document:, metadata: nil, embedder: nil, collection_name: nil, keep_document: true)
20
+ @collection_name = collection_name
21
+ @document = document
22
+ @metadata = metadata
23
+ @embedder = embedder
24
+ @keep_document = keep_document
25
+ end
26
+ end
27
+
18
28
  # Methods to be added to the model class.
19
29
  module ClassMethods
20
- def chromable(document:, metadata: nil, embedder: nil, collection_name: nil)
21
- self.collection_name = (collection_name.presence || name.underscore.pluralize)
22
- self.document = document
23
- self.metadata = metadata
24
- self.embedder = embedder
30
+ def self.extended(base)
31
+ class << base
32
+ alias_method :collection, :chroma_collection unless method_defined? :collection
33
+ alias_method :delete_collection, :chroma_delete_collection unless method_defined? :delete_collection
34
+ alias_method :query, :chroma_query unless method_defined? :query
35
+ end
36
+
37
+ base.cattr_accessor :chromable_settings
38
+ end
39
+
40
+ def chromable(**options)
41
+ options[:collection_name] ||= name.underscore.pluralize
42
+
43
+ self.chromable_settings = Settings.new(**options)
25
44
  end
26
45
 
27
46
  def chroma_collection
28
- Chroma::Resources::Collection.get_or_create(collection_name)
47
+ Chroma::Resources::Collection.get_or_create(chromable_settings.collection_name)
48
+ end
49
+
50
+ def chroma_delete_collection
51
+ Chroma::Resources::Collection.delete(chromable_settings.collection_name)
29
52
  end
30
53
 
31
54
  def chroma_query( # rubocop:disable Metrics/ParameterLists
32
- query:,
55
+ text:,
33
56
  results: 10,
34
57
  where: {},
35
58
  where_document: {},
@@ -37,44 +60,60 @@ module Chromable
37
60
  **embedder_options
38
61
  )
39
62
  find(chroma_collection.query(
40
- query_embeddings: [send(embedder, query, **embedder_options)],
63
+ query_embeddings: [send(chromable_settings.embedder, text, **embedder_options)],
41
64
  results: results,
42
65
  where: where,
43
66
  where_document: where_document,
44
67
  include: include
45
68
  ).map(&:id))
46
69
  end
47
-
48
- alias collection chroma_collection unless method_defined? :collection
49
- alias query chroma_query unless method_defined? :query
50
70
  end
51
71
 
52
- def chroma_embedding
53
- self.class.chroma_collection.get(ids: [id])[0]
54
- end
72
+ # Methods to be added to the model instances.
73
+ module InstanceMethods
74
+ def self.included(base)
75
+ base.instance_eval do
76
+ # rubocop:disable Style/Alias
77
+ alias_method :embedding, :chroma_embedding unless method_defined? :embedding
78
+ alias_method :upsert_embedding, :chroma_upsert_embedding unless method_defined? :upsert_embedding
79
+ alias_method :destroy_embedding, :chroma_destroy_embedding unless method_defined? :destroy_embedding
80
+ # rubocop:enable Style/Alias
81
+ end
82
+ end
55
83
 
56
- def chroma_upsert_embedding
57
- self.class.chroma_collection.upsert(build_embedding)
58
- end
84
+ def chroma_embedding
85
+ self.class.chroma_collection.get(ids: [id])[0]
86
+ end
59
87
 
60
- def chroma_destroy_embedding
61
- self.class.chroma_collection.delete(ids: [id])
62
- end
88
+ def chroma_upsert_embedding
89
+ self.class.chroma_collection.upsert(build_embedding)
90
+ end
91
+
92
+ def chroma_destroy_embedding
93
+ self.class.chroma_collection.delete(ids: [id])
94
+ end
63
95
 
64
- alias embedding chroma_embedding unless method_defined? :embedding
65
- alias upsert_embedding chroma_upsert_embedding unless method_defined? :upsert_embedding
66
- alias destroy_embedding chroma_destroy_embedding unless method_defined? :destroy_embedding
96
+ private
67
97
 
68
- private
98
+ def build_embedding
99
+ Chroma::Resources::Embedding.new(
100
+ id: id,
101
+ document: document_to_embed,
102
+ embedding: document_embedding,
103
+ metadata: embedding_metadata
104
+ )
105
+ end
69
106
 
70
- def build_embedding
71
- document = send(self.class.document)
107
+ def document_to_embed
108
+ chromable_settings.keep_document ? send(chromable_settings.document) : nil
109
+ end
72
110
 
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
- )
111
+ def document_embedding
112
+ chromable_settings.embedder && self.class.send(chromable_settings.embedder, send(chromable_settings.document))
113
+ end
114
+
115
+ def embedding_metadata
116
+ chromable_settings.metadata&.index_with { |attribute| send(attribute) }
117
+ end
79
118
  end
80
119
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chromable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.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-11 00:00:00.000000000 Z
11
+ date: 2023-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chroma-db