pinecone 0.1.71 → 1.1.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: ea82946a00b57e8d81af48478eee15aa1f0a17a22316d982878f1033aa57dc7f
4
- data.tar.gz: 6db21ac3336d691bce0064f2c22a8e1f1f5ced9a725e5b76eec14a0752c5d488
3
+ metadata.gz: c9e5f89bdb821f056dde85c82168420d575599d116508b083fb987ea7b3b60da
4
+ data.tar.gz: b4d1da67d606505ca251db63cc63a9077d363e92425ddfeb4ea55263af30aac6
5
5
  SHA512:
6
- metadata.gz: 6265199be8db129c2b428cebef001249cc6827819643e19421eea23727484c69bd7054eb0eb0e3a3fc9e332eecfadaed900a618664bdb8fc61f320b9e4833c6b
7
- data.tar.gz: '0913f7fe938dddfc78a150847f73da703b375250d55150c1718ee408b0f8b2012321db7c10a4de2fbb5e6fdf8f15ec8a3e1c27067903b807a0574de85f2455da'
6
+ metadata.gz: c429ec85b521a797a73597a6cba93b77e4892e84176064079367605c8436b15709aa03fd7ab563240c96bc8406c6b805c3d43bb7cc7f91c8c7ad1b016724acfe
7
+ data.tar.gz: 749c157e0650086c2365023cf8a9626ef04fd4bce9b5eac886de5007480c64318aa0c3312ea1795713ca08475c5e2f5396130aaabe2bb84d5d853d52969c12d1
@@ -39,8 +39,9 @@ module Pinecone
39
39
  end
40
40
 
41
41
  # This is a very confusing naming convention
42
+ # Pinecone's reference now delineates between 'control plane' and 'data plane' which we'll reflect eventually
42
43
  def index(index_name)
43
- @index ||= Pinecone::Vector.new(index_name)
44
+ Pinecone::Vector.new(index_name)
44
45
  end
45
46
  end
46
- end
47
+ end
@@ -1,19 +1,20 @@
1
1
  module Pinecone
2
2
  class Collection
3
3
  include HTTParty
4
+ parser Pinecone::ResponseParser
4
5
 
5
6
  def initialize
6
- self.class.base_uri "https://controller.#{Pinecone.configuration.environment}.pinecone.io"
7
+ self.class.base_uri "https://api.pinecone.io"
7
8
 
8
9
  @headers = {
9
10
  "Content-Type" => "application/json",
10
11
  "Accept" => "application/json",
11
- "Api-Key" => Pinecone.configuration.api_key,
12
+ "Api-Key" => Pinecone.configuration.api_key
12
13
  }
13
14
  end
14
15
 
15
16
  def list
16
- self.class.get('/collections', options)
17
+ self.class.get("/collections", options)
17
18
  end
18
19
 
19
20
  def describe(collection_name)
@@ -22,7 +23,7 @@ module Pinecone
22
23
 
23
24
  def create(body)
24
25
  payload = options.merge(body: body.to_json)
25
- self.class.post('/collections', payload)
26
+ self.class.post("/collections", payload)
26
27
  end
27
28
 
28
29
  def delete(collection_name)
@@ -31,8 +32,8 @@ module Pinecone
31
32
 
32
33
  def options
33
34
  {
34
- headers: @headers,
35
+ headers: @headers
35
36
  }
36
37
  end
37
38
  end
38
- end
39
+ end
@@ -1,42 +1,43 @@
1
1
  module Pinecone
2
2
  class Index
3
3
  include HTTParty
4
+ parser Pinecone::ResponseParser
4
5
 
5
6
  def initialize
6
- self.class.base_uri "https://controller.#{Pinecone.configuration.environment}.pinecone.io"
7
+ self.class.base_uri "https://api.pinecone.io"
7
8
  @headers = {
8
9
  "Content-Type" => "application/json",
9
10
  "Accept" => "application/json",
10
- "Api-Key" => Pinecone.configuration.api_key,
11
+ "Api-Key" => Pinecone.configuration.api_key
11
12
  }
12
13
  end
13
14
 
14
15
  def list
15
- self.class.get('/databases', options)
16
+ self.class.get("/indexes", options)
16
17
  end
17
18
 
18
19
  def describe(index_name)
19
- self.class.get("/databases/#{index_name}", options)
20
+ self.class.get("/indexes/#{index_name}", options)
20
21
  end
21
-
22
+
22
23
  def create(body)
23
24
  payload = options.merge(body: body.to_json)
24
- self.class.post('/databases', payload)
25
+ self.class.post("/indexes", payload)
25
26
  end
26
27
 
27
28
  def delete(index_name)
28
- self.class.delete("/databases/#{index_name}", options)
29
+ self.class.delete("/indexes/#{index_name}", options)
29
30
  end
30
31
 
31
32
  def configure(index_name, body)
32
33
  payload = options.merge(body: body.to_json)
33
- self.class.patch("/databases/#{index_name}", payload)
34
+ self.class.patch("/indexes/#{index_name}", payload)
34
35
  end
35
36
 
36
37
  def options
37
38
  {
38
- headers: @headers,
39
+ headers: @headers
39
40
  }
40
41
  end
41
42
  end
42
- end
43
+ end
@@ -0,0 +1,16 @@
1
+ module Pinecone
2
+ class ResponseParser < HTTParty::Parser
3
+ # standard:disable Naming/ConstantName
4
+ SupportedFormats = {
5
+ "application/json" => :json,
6
+ "text/plain" => :json
7
+ }
8
+ # standard:enable Naming/ConstantName
9
+
10
+ def json
11
+ JSON.parse(body)
12
+ rescue
13
+ body
14
+ end
15
+ end
16
+ end
@@ -6,9 +6,9 @@ require "dry-validation"
6
6
  module Types
7
7
  include Dry.Types()
8
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']
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
12
  end
13
13
 
14
14
  module Pinecone
@@ -50,14 +50,14 @@ module Pinecone
50
50
 
51
51
  def to_filter(input)
52
52
  return false unless input.is_a?(Hash)
53
- return Filter.new(input)
53
+ Filter.new(input)
54
54
  end
55
55
  end
56
56
 
57
57
  def self.new(input)
58
58
  validation = FilterContract.new.call(input)
59
59
  if validation.success?
60
- super(input)
60
+ super
61
61
  else
62
62
  raise ArgumentError.new(validation.errors.to_h.inspect)
63
63
  end
@@ -68,4 +68,4 @@ module Pinecone
68
68
  end
69
69
  end
70
70
  end
71
- end
71
+ end
@@ -29,22 +29,22 @@ module Pinecone
29
29
 
30
30
  schema schema.strict
31
31
 
32
- attribute :namespace, Dry::Types['string'].default("")
33
- attribute :include_values, Dry::Types['bool'].default(false)
34
- attribute :include_metadata, Dry::Types['bool'].default(true)
35
- attribute :top_k, Dry::Types['integer'].default(10)
36
- attribute? :vector, Dry::Types['array'].of(Dry::Types['float'] | Dry::Types['integer'])
32
+ attribute :namespace, Dry::Types["string"].default("")
33
+ attribute :include_values, Dry::Types["bool"].default(false)
34
+ attribute :include_metadata, Dry::Types["bool"].default(true)
35
+ attribute :top_k, Dry::Types["integer"].default(10)
36
+ attribute? :vector, Dry::Types["array"].of(Dry::Types["float"] | Dry::Types["integer"])
37
37
  # Disabled contract since it wasn't carrying forward attributes to to_json
38
38
  # See failing test in query_spec.rb
39
- # attribute? :filter, Filter
40
- attribute? :filter, Dry::Types['hash']
39
+ # attribute? :filter, Filter
40
+ attribute? :filter, Dry::Types["hash"]
41
41
  attribute? :sparse_vector, SparseVector
42
- attribute? :id, Dry::Types['string']
42
+ attribute? :id, Dry::Types["string"]
43
43
 
44
44
  def self.new(input)
45
45
  validation = QueryContract.new.call(input)
46
46
  if validation.success?
47
- super(input)
47
+ super
48
48
  else
49
49
  raise ArgumentError.new(validation.errors.to_h.inspect)
50
50
  end
@@ -53,10 +53,10 @@ module Pinecone
53
53
  def to_json
54
54
  to_h.map do |key, value|
55
55
  [key.to_s.split("_").map.with_index do |word, index|
56
- index == 0 ? word : word.capitalize
56
+ (index == 0) ? word : word.capitalize
57
57
  end.join.to_sym, value]
58
58
  end.to_h.to_json
59
59
  end
60
60
  end
61
61
  end
62
- end
62
+ end
@@ -24,17 +24,17 @@ module Pinecone
24
24
  end
25
25
  end
26
26
 
27
- attribute :indices, Dry::Types['array'].of(Dry::Types['integer'])
28
- attribute :values, Dry::Types['array'].of(Dry::Types['float'] | Dry::Types['integer'])
27
+ attribute :indices, Dry::Types["array"].of(Dry::Types["integer"])
28
+ attribute :values, Dry::Types["array"].of(Dry::Types["float"] | Dry::Types["integer"])
29
29
 
30
30
  def self.new(input)
31
31
  validation = SparseVectorContract.new.call(input)
32
32
  if validation.success?
33
- super(input)
33
+ super
34
34
  else
35
35
  raise ArgumentError.new(validation.errors.to_h.inspect)
36
36
  end
37
37
  end
38
38
  end
39
39
  end
40
- end
40
+ end
@@ -5,46 +5,103 @@ require "pinecone/vector/sparse_vector"
5
5
  module Pinecone
6
6
  class Vector
7
7
  include HTTParty
8
+ parser Pinecone::ResponseParser
9
+
10
+ attr_reader :base_uri
8
11
 
9
12
  def initialize(index_name)
10
- self.class.base_uri set_base_uri(index_name)
13
+ @base_uri = set_base_uri(index_name)
11
14
 
12
15
  @headers = {
13
16
  "Content-Type" => "application/json",
14
17
  "Accept" => "application/json",
15
- "Api-Key" => Pinecone.configuration.api_key,
18
+ "Api-Key" => Pinecone.configuration.api_key
16
19
  }
17
20
  end
18
21
 
19
- def delete(namespace: "", ids: [], delete_all: false)
22
+ def delete(namespace: "", ids: [], delete_all: false, filter: {})
20
23
  inputs = {
21
- "namespace": namespace,
22
- "ids": ids,
23
- "deleteAll": delete_all,
24
- }.to_json
25
- payload = options.merge(body: inputs)
26
- self.class.post('/vectors/delete', payload)
24
+ namespace: namespace,
25
+ ids: ids,
26
+ deleteAll: delete_all,
27
+ filter: filter
28
+ }
29
+ inputs.delete(:filter) if delete_all || ids.any?
30
+ payload = options.merge(body: inputs.to_json)
31
+ self.class.post("#{@base_uri}/vectors/delete", payload)
27
32
  end
28
33
 
29
34
  def fetch(namespace: "", ids: [])
30
- query_string = URI.encode_www_form({ namespace: namespace, ids: ids})
31
- self.class.get("/vectors/fetch?#{query_string}", options)
35
+ query_string = URI.encode_www_form({namespace: namespace, ids: ids})
36
+ self.class.get("#{@base_uri}/vectors/fetch?#{query_string}", options)
37
+ end
38
+
39
+ def list(prefix: nil, limit: nil, namespace: nil, &block)
40
+ all_ids = []
41
+ pagination_token = nil
42
+ total_fetched = 0
43
+
44
+ loop do
45
+ current_limit = limit.nil? ? 100 : [limit - total_fetched, 100].min
46
+
47
+ response = list_paginated(
48
+ prefix: prefix,
49
+ limit: current_limit,
50
+ pagination_token: pagination_token,
51
+ namespace: namespace
52
+ )
53
+
54
+ break unless response.success?
55
+
56
+ results = response.parsed_response
57
+ ids = results["vectors"]&.map { |v| v["id"] } || []
58
+
59
+ if block
60
+ yield ids
61
+ else
62
+ all_ids.concat(ids)
63
+ end
64
+
65
+ total_fetched += ids.length
66
+ pagination_token = results.dig("pagination", "next")
67
+
68
+ break if ids.empty?
69
+ break if limit && total_fetched >= limit
70
+ break if pagination_token.nil? || pagination_token.empty?
71
+ end
72
+
73
+ if block
74
+ nil
75
+ else
76
+ limit ? all_ids.first(limit) : all_ids
77
+ end
78
+ end
79
+
80
+ def list_paginated(prefix: nil, limit: nil, pagination_token: nil, namespace: nil)
81
+ query_params = {}
82
+ query_params["prefix"] = prefix if prefix
83
+ query_params["limit"] = limit if limit
84
+ query_params["paginationToken"] = pagination_token if pagination_token
85
+ query_params["namespace"] = namespace if namespace
86
+
87
+ query_string = URI.encode_www_form(query_params)
88
+ self.class.get("#{@base_uri}/vectors/list?#{query_string}", options)
32
89
  end
33
90
 
34
91
  def upsert(body)
35
92
  payload = options.merge(body: body.to_json)
36
- self.class.post('/vectors/upsert', payload)
93
+ self.class.post("#{@base_uri}/vectors/upsert", payload)
37
94
  end
38
95
 
39
96
  def query(query)
40
97
  object = query.is_a?(Pinecone::Vector::Query) ? query : Pinecone::Vector::Query.new(query)
41
98
  payload = options.merge(body: object.to_json)
42
- self.class.post('/query', payload)
99
+ self.class.post("#{@base_uri}/query", payload)
43
100
  end
44
101
 
45
102
  def update(id:, values: [], sparse_values: {indices: [], values: []}, set_metadata: {}, namespace: "")
46
103
  inputs = {
47
- "id": id
104
+ id: id
48
105
  }
49
106
  inputs["values"] = values unless values.empty?
50
107
  inputs["sparseValues"] = sparse_values unless sparse_values[:indices].empty? || sparse_values[:values].empty?
@@ -52,7 +109,7 @@ module Pinecone
52
109
  inputs["namespace"] = namespace unless namespace.empty?
53
110
 
54
111
  payload = options.merge(body: inputs.to_json)
55
- self.class.post('/vectors/update', payload)
112
+ self.class.post("#{@base_uri}/vectors/update", payload)
56
113
  end
57
114
 
58
115
  def describe_index_stats(filter: {})
@@ -61,13 +118,12 @@ module Pinecone
61
118
  else
62
119
  options.merge(body: {filter: filter}.to_json)
63
120
  end
64
- self.class.post('/describe_index_stats', payload)
121
+ self.class.post("#{@base_uri}/describe_index_stats", payload)
65
122
  end
66
123
 
67
-
68
124
  def options
69
125
  {
70
- headers: @headers,
126
+ headers: @headers
71
127
  }
72
128
  end
73
129
 
@@ -77,8 +133,8 @@ module Pinecone
77
133
  def set_base_uri(index_name)
78
134
  index_description = Pinecone::Index.new.describe(index_name)
79
135
  raise Pinecone::IndexNotFoundError, "Index #{index_name} does not exist" if index_description.code != 200
80
- uri = index_description.parsed_response["status"]["host"]
136
+ uri = index_description.parsed_response["host"]
81
137
  "https://#{uri}"
82
138
  end
83
139
  end
84
- end
140
+ end
@@ -1,3 +1,3 @@
1
1
  module Pinecone
2
- VERSION = "0.1.71".freeze
3
- end
2
+ VERSION = "1.1.0".freeze
3
+ end
data/lib/pinecone.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "httparty"
2
2
 
3
+ require "pinecone/response_parser"
3
4
  require "pinecone/client"
4
5
  require "pinecone/index"
5
6
  require "pinecone/vector"
@@ -8,14 +9,16 @@ require "pinecone/version"
8
9
 
9
10
  module Pinecone
10
11
  class ConfigurationError < StandardError; end
12
+
11
13
  class IndexNotFoundError < StandardError; end
14
+
12
15
  class Configuration
13
16
  attr_writer :api_key, :base_uri, :environment
14
17
 
15
18
  def initialize
16
- @api_key = nil
19
+ @api_key = nil
17
20
  @environment = nil
18
- @base_uri = nil
21
+ @base_uri = nil
19
22
  end
20
23
 
21
24
  def api_key
@@ -48,4 +51,4 @@ module Pinecone
48
51
  def self.configure
49
52
  yield(configuration)
50
53
  end
51
- end
54
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pinecone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.71
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Carleton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-28 00:00:00.000000000 Z
11
+ date: 2024-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.21.0
19
+ version: 0.22.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.21.0
26
+ version: 0.22.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: dry-struct
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,104 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.10.0
55
- - !ruby/object:Gem::Dependency
56
- name: dotenv
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '2.8'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '2.8'
69
- - !ruby/object:Gem::Dependency
70
- name: awesome_print
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '1.9'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '1.9'
83
- - !ruby/object:Gem::Dependency
84
- name: rake
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '13.0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '13.0'
97
- - !ruby/object:Gem::Dependency
98
- name: debug
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '1.7'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '1.7'
111
- - !ruby/object:Gem::Dependency
112
- name: rspec
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '3.12'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '3.12'
125
- - !ruby/object:Gem::Dependency
126
- name: webmock
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '3.14'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '3.14'
139
- - !ruby/object:Gem::Dependency
140
- name: vcr
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '6.1'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: '6.1'
153
55
  description: Ruby client library which includes index and vector operations to upload
154
56
  embeddings into Pinecone and do similarity searches on them.
155
57
  email: scott@extrayarn.com
@@ -161,6 +63,7 @@ files:
161
63
  - lib/pinecone/client.rb
162
64
  - lib/pinecone/collection.rb
163
65
  - lib/pinecone/index.rb
66
+ - lib/pinecone/response_parser.rb
164
67
  - lib/pinecone/vector.rb
165
68
  - lib/pinecone/vector/filter.rb
166
69
  - lib/pinecone/vector/query.rb
@@ -179,14 +82,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
179
82
  requirements:
180
83
  - - ">="
181
84
  - !ruby/object:Gem::Version
182
- version: '0'
85
+ version: '3'
183
86
  required_rubygems_version: !ruby/object:Gem::Requirement
184
87
  requirements:
185
88
  - - ">="
186
89
  - !ruby/object:Gem::Version
187
90
  version: '0'
188
91
  requirements: []
189
- rubygems_version: 3.4.3
92
+ rubygems_version: 3.5.15
190
93
  signing_key:
191
94
  specification_version: 4
192
95
  summary: Ruby client library for Pinecone Vector DB