roseflow-pinecone 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Roseflow
4
+ module Pinecone
5
+ module Vectors
6
+ module Common
7
+ def self.extended(base_class)
8
+ base_class.extend ClassMethods
9
+ end
10
+
11
+ def self.included(base_class)
12
+ base_class.extend ClassMethods
13
+ end
14
+
15
+ module ClassMethods
16
+ def self.new(input)
17
+ validation = self.contract_object.new.call(input)
18
+ if validation.success?
19
+ super(input)
20
+ else
21
+ raise ArgumentError.new(validation.errors.to_h.inspect)
22
+ end
23
+ end
24
+ end
25
+
26
+ def to_json
27
+ to_h.map do |key, value|
28
+ [key.to_s.split("_").map.with_index do |word, index|
29
+ index == 0 ? word : word.capitalize
30
+ end.join.to_sym, value]
31
+ end.to_h.to_json
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-struct"
4
+ require "dry-validation"
5
+
6
+ require "roseflow/pinecone/object"
7
+ require "roseflow/pinecone/vectors/filter"
8
+ require "roseflow/pinecone/vectors/common"
9
+
10
+ module Types
11
+ include Dry.Types()
12
+ end
13
+
14
+ module Roseflow
15
+ module Pinecone
16
+ class Vector
17
+ class Deletion < PineconeObject
18
+ include Roseflow::Pinecone::Vectors::Common
19
+
20
+ class DeletionContract < Dry::Validation::Contract
21
+ params do
22
+ optional(:ids).filled(:array)
23
+ optional(:namespace).filled(:string)
24
+ optional(:filter).filled
25
+ optional(:delete_all).filled(:bool)
26
+ end
27
+ end
28
+
29
+ contract_object DeletionContract
30
+
31
+ attribute? :ids, Dry::Types['array'].of(Dry::Types['string'])
32
+ attribute? :namespace, Dry::Types['string']
33
+ attribute? :filter, Types.Instance(Filter)
34
+ attribute? :delete_all, Dry::Types['bool'].default(false)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-struct"
4
+ require "dry-validation"
5
+
6
+ module Types
7
+ include Dry.Types()
8
+
9
+ StringOrNumberOrBoolean = Dry::Types['string'] | Dry::Types['integer'] | Dry::Types['float'] | Dry::Types['bool']
10
+ StringOrNumber = Dry::Types['string'] | Dry::Types['integer'] | Dry::Types['float']
11
+ Number = Dry::Types['integer'] | Dry::Types['float']
12
+ end
13
+
14
+ module Roseflow
15
+ module Pinecone
16
+ class Vector
17
+ class Filter < Hash
18
+ class FilterContract < Dry::Validation::Contract
19
+ schema do
20
+ optional(:$and).filled(:array)
21
+ optional(:$or).filled(:array)
22
+ optional(:$eq).filled(Types::StringOrNumberOrBoolean)
23
+ optional(:$ne).filled(Types::StringOrNumberOrBoolean)
24
+ optional(:$gt).filled(Types::Number)
25
+ optional(:$gte).filled(Types::Number)
26
+ optional(:$lt).filled(Types::Number)
27
+ optional(:$lte).filled(Types::Number)
28
+ optional(:$in).filled(:array).each(Types::StringOrNumber)
29
+ optional(:$nin).filled(:array).each(Types::StringOrNumber)
30
+ end
31
+
32
+ rule(:$and) do
33
+ if key?
34
+ key(:$and).failure("'$any' must be an array") unless value.is_a?(Array)
35
+
36
+ value.each do |v|
37
+ key(:$and).failure("'$any' must be an array of filters") unless v.is_a?(Filter) || to_filter(v).is_a?(Filter)
38
+ end
39
+ end
40
+ end
41
+
42
+ rule(:$or) do
43
+ if key?
44
+ key(:$or).failure("'$or' must be an array") unless value.is_a?(Array)
45
+
46
+ value.each do |v|
47
+ key(:$or).failure("'$or' must be an array of filters") unless v.is_a?(Filter) || to_filter(v).is_a?(Filter)
48
+ end
49
+ end
50
+ end
51
+
52
+ def to_filter(input)
53
+ return false unless input.is_a?(Hash)
54
+ return Filter.new(input)
55
+ end
56
+ end
57
+
58
+ def self.new(input)
59
+ validation = FilterContract.new.call(input)
60
+ if validation.success?
61
+ super(input)
62
+ else
63
+ raise ArgumentError.new(validation.errors.to_h.inspect)
64
+ end
65
+ end
66
+
67
+ def self.default?
68
+ nil
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-struct"
4
+ require "dry-validation"
5
+
6
+ require "roseflow/pinecone/vectors/filter"
7
+ require "roseflow/pinecone/vectors/sparse_vector"
8
+
9
+ module Types
10
+ include Dry.Types()
11
+ end
12
+
13
+ module Roseflow
14
+ module Pinecone
15
+ class Vector
16
+ class Query < PineconeObject
17
+ include Roseflow::Pinecone::Vectors::Common
18
+
19
+ class QueryContract < Dry::Validation::Contract
20
+ params do
21
+ optional(:vector).filled(:array)
22
+ optional(:id).filled(:string)
23
+ end
24
+
25
+ rule(:vector, :id) do
26
+ if !values[:vector].nil? && !values[:id].nil?
27
+ key(:vector).failure("Only one of vector or id can be specified")
28
+ key(:id).failure("Only one of vector or id can be specified")
29
+ end
30
+ end
31
+ end
32
+
33
+ contract_object QueryContract
34
+
35
+ schema schema.strict
36
+
37
+ attribute :namespace, Dry::Types['string'].default("")
38
+ attribute :include_values, Dry::Types['bool'].default(false)
39
+ attribute :include_metadata, Dry::Types['bool'].default(true)
40
+ attribute :top_k, Dry::Types['integer'].default(10)
41
+ attribute? :vector, Dry::Types['array'].of(Dry::Types['float'] | Dry::Types['integer'])
42
+ attribute? :filter, Filter
43
+ attribute? :sparse_vector, SparseVector
44
+ attribute? :id, Dry::Types['string']
45
+
46
+ def self.new(input)
47
+ validation = self.contract_object.new.call(input)
48
+ if validation.success?
49
+ super(input)
50
+ else
51
+ raise ArgumentError.new(validation.errors.to_h.inspect)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-struct"
4
+ require "dry-validation"
5
+
6
+ require "roseflow/pinecone/object"
7
+ require "roseflow/pinecone/vectors/common"
8
+
9
+ module Types
10
+ include Dry.Types()
11
+ end
12
+
13
+ module Roseflow
14
+ module Pinecone
15
+ class Vector
16
+ class SparseVector < PineconeObject
17
+ include Roseflow::Pinecone::Vectors::Common
18
+
19
+ class SparseVectorContract < Dry::Validation::Contract
20
+ params do
21
+ required(:indices).filled(:array)
22
+ required(:values).filled(:array)
23
+ end
24
+
25
+ rule(:indices, :values) do
26
+ unless values[:indices].size === values[:values].size
27
+ key(:indices).failure("Indices and values must be the same size")
28
+ key(:values).failure("Indices and values must be the same size")
29
+ end
30
+ end
31
+ end
32
+
33
+ contract_object SparseVectorContract
34
+
35
+ attribute :indices, Dry::Types['array'].of(Dry::Types['integer'])
36
+ attribute :values, Dry::Types['array'].of(Dry::Types['float'] | Dry::Types['integer'])
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-struct"
4
+ require "dry-validation"
5
+
6
+ require "roseflow/pinecone/object"
7
+ require "roseflow/pinecone/vectors/sparse_vector"
8
+ require "roseflow/pinecone/vectors/common"
9
+
10
+ module Types
11
+ include Dry.Types()
12
+ end
13
+
14
+ module Roseflow
15
+ module Pinecone
16
+ class Vector
17
+ class Update < PineconeObject
18
+ include Roseflow::Pinecone::Vectors::Common
19
+
20
+ class UpdateContract < Dry::Validation::Contract
21
+ params do
22
+ required(:id).filled(:string)
23
+ optional(:namespace).filled(:string)
24
+ optional(:values).filled(:array)
25
+ optional(:sparse_values).filled
26
+ optional(:metadata).filled(:hash)
27
+ end
28
+ end
29
+
30
+ contract_object UpdateContract
31
+
32
+ attribute :id, Dry::Types['string']
33
+ attribute? :namespace, Dry::Types['string'].optional
34
+ attribute? :values, Dry::Types['array'].of(Dry::Types['float']).optional
35
+ attribute? :sparse_values, SparseVector.optional
36
+ attribute? :metadata, Dry::Types['hash'].optional
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-struct"
4
+
5
+ require "roseflow/pinecone/object"
6
+ require "roseflow/pinecone/vectors/sparse_vector"
7
+ require "roseflow/pinecone/vectors/vector_object"
8
+ require "roseflow/pinecone/vectors/common"
9
+
10
+ module Types
11
+ include Dry.Types()
12
+ end
13
+
14
+ module Roseflow
15
+ module Pinecone
16
+ class Vector
17
+ class Upsert < PineconeObject
18
+ include Roseflow::Pinecone::Vectors::Common
19
+
20
+ class UpsertContract < Dry::Validation::Contract
21
+ params do
22
+ required(:vectors).filled(:array)
23
+ optional(:namespace).filled(:string)
24
+ end
25
+ end
26
+
27
+ contract_object UpsertContract
28
+
29
+ attribute :vectors, Dry::Types['array'].of(VectorObject)
30
+ attribute? :namespace, Dry::Types['string'].optional
31
+
32
+ def self.from(data)
33
+ raise ArgumentError, "Data must be a valid upsert hash" unless data.is_a?(Hash) && data.keys.include?(:vectors)
34
+ new(
35
+ vectors: data[:vectors].map { |vector| VectorObject.new(id: vector[:id], values: vector[:values]) },
36
+ namespace: data[:namespace]
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-struct"
4
+ require "dry-validation"
5
+
6
+ require "roseflow/pinecone/object"
7
+ require "roseflow/pinecone/vectors/sparse_vector"
8
+ require "roseflow/pinecone/vectors/common"
9
+
10
+ module Types
11
+ include Dry.Types()
12
+
13
+ Number = Types::Coercible::Float
14
+ # SparseVector = Roseflow::Pinecone::Vector::SparseVector
15
+ end
16
+
17
+ module Roseflow
18
+ module Pinecone
19
+ class Vector
20
+ class VectorObject < PineconeObject
21
+ include Roseflow::Pinecone::Vectors::Common
22
+ transform_keys(&:to_sym)
23
+
24
+ class VectorObjectContract < Dry::Validation::Contract
25
+ params do
26
+ required(:id).filled(:string)
27
+ required(:values).filled(:array)
28
+ optional(:sparse_values).filled
29
+ optional(:metadata).filled(:hash)
30
+ end
31
+ end
32
+
33
+ contract_object VectorObjectContract
34
+
35
+ attribute :id, Dry::Types['string']
36
+ attribute :values, Dry::Types['array'].of(Types::Number)
37
+ attribute? :score, Types::Number.optional
38
+ attribute? :sparse_values, SparseVector.optional
39
+ attribute? :metadata, Dry::Types['hash'].optional
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Roseflow
4
+ module Pinecone
5
+ def self.gem_version
6
+ Gem::Version.new VERSION::STRING
7
+ end
8
+
9
+ module VERSION
10
+ MAJOR = 0
11
+ MINOR = 1
12
+ PATCH = 0
13
+ PRE = nil
14
+
15
+ STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "pinecone/version"
4
+
5
+ require "roseflow/pinecone/client"
6
+ require "roseflow/pinecone/collection"
7
+ require "roseflow/pinecone/config"
8
+ require "roseflow/pinecone/response"
9
+
10
+ require "dry-struct"
11
+
12
+ module Types
13
+ include Dry.Types()
14
+ end
15
+
16
+ module Roseflow
17
+ module Pinecone
18
+ class Error < StandardError; end
19
+ class IndexURLNotSetError < Error; end
20
+ end
21
+ end
22
+
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/roseflow/pinecone/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "roseflow-pinecone"
7
+ spec.version = Roseflow::Pinecone.gem_version
8
+ spec.authors = ["Lauri Jutila"]
9
+ spec.email = ["git@laurijutila.com"]
10
+
11
+ spec.summary = "Roseflow meets Pinecone"
12
+ spec.description = "Pinecone vector database integration and support for Roseflow."
13
+ spec.homepage = "https://github.com/roseflow-ai/roseflow-pinecone"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.2.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/roseflow-ai/roseflow-pinecone"
19
+ spec.metadata["changelog_uri"] = "https://github.com/roseflow-ai/roseflow-pinecone/blob/master/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
26
+ end
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ # Uncomment to register a new dependency of your gem
33
+ spec.add_dependency "activesupport"
34
+ spec.add_dependency "anyway_config", "~> 2.0"
35
+ spec.add_dependency "dry-struct"
36
+ spec.add_dependency "dry-validation"
37
+ spec.add_dependency "faraday"
38
+ spec.add_dependency "faraday-retry"
39
+
40
+ spec.add_development_dependency "awesome_print"
41
+ spec.add_development_dependency "pry"
42
+ spec.add_development_dependency "roseflow"
43
+ spec.add_development_dependency "webmock"
44
+ spec.add_development_dependency "vcr"
45
+
46
+ # For more information and examples about making a new gem, check out our
47
+ # guide at: https://bundler.io/guides/creating_gem.html
48
+ end
@@ -0,0 +1,6 @@
1
+ module Roseflow
2
+ module Pinecone
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end