vectra-client 0.2.0 → 0.2.2
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 +4 -4
- data/CHANGELOG.md +27 -14
- data/README.md +140 -328
- data/Rakefile +1 -1
- data/docs/Gemfile +10 -0
- data/docs/_config.yml +20 -0
- data/docs/_layouts/default.html +14 -0
- data/docs/_layouts/home.html +33 -0
- data/docs/_layouts/page.html +20 -0
- data/docs/_site/api/overview/index.html +145 -0
- data/docs/_site/assets/main.css +649 -0
- data/docs/_site/assets/main.css.map +1 -0
- data/docs/_site/assets/minima-social-icons.svg +33 -0
- data/docs/_site/assets/style.css +295 -0
- data/docs/_site/community/contributing/index.html +110 -0
- data/docs/_site/examples/basic-usage/index.html +117 -0
- data/docs/_site/examples/index.html +58 -0
- data/docs/_site/feed.xml +1 -0
- data/docs/_site/guides/getting-started/index.html +106 -0
- data/docs/_site/guides/installation/index.html +82 -0
- data/docs/_site/index.html +92 -0
- data/docs/_site/providers/index.html +119 -0
- data/docs/_site/providers/pgvector/index.html +155 -0
- data/docs/_site/providers/pinecone/index.html +121 -0
- data/docs/_site/providers/qdrant/index.html +124 -0
- data/docs/_site/providers/weaviate/index.html +123 -0
- data/docs/_site/robots.txt +1 -0
- data/docs/_site/sitemap.xml +39 -0
- data/docs/api/overview.md +126 -0
- data/docs/assets/style.css +295 -0
- data/docs/community/contributing.md +89 -0
- data/docs/examples/basic-usage.md +102 -0
- data/docs/examples/index.md +32 -0
- data/docs/guides/getting-started.md +90 -0
- data/docs/guides/installation.md +67 -0
- data/docs/index.md +53 -0
- data/docs/providers/index.md +62 -0
- data/docs/providers/pgvector.md +95 -0
- data/docs/providers/pinecone.md +72 -0
- data/docs/providers/qdrant.md +73 -0
- data/docs/providers/weaviate.md +72 -0
- data/lib/vectra/configuration.rb +10 -1
- data/lib/vectra/providers/base.rb +10 -0
- data/lib/vectra/providers/qdrant.rb +399 -12
- data/lib/vectra/version.rb +1 -1
- data/lib/vectra.rb +9 -2
- data/netlify.toml +12 -0
- metadata +43 -9
- data/IMPLEMENTATION_GUIDE.md +0 -686
- data/NEW_FEATURES_v0.2.0.md +0 -459
- data/RELEASE_CHECKLIST_v0.2.0.md +0 -383
- data/USAGE_EXAMPLES.md +0 -787
|
@@ -2,47 +2,434 @@
|
|
|
2
2
|
|
|
3
3
|
module Vectra
|
|
4
4
|
module Providers
|
|
5
|
-
# Qdrant vector database provider
|
|
5
|
+
# Qdrant vector database provider
|
|
6
6
|
#
|
|
7
|
-
#
|
|
7
|
+
# Qdrant is an open-source vector similarity search engine with extended filtering support.
|
|
8
8
|
#
|
|
9
|
+
# @example Basic usage
|
|
10
|
+
# Vectra.configure do |config|
|
|
11
|
+
# config.provider = :qdrant
|
|
12
|
+
# config.api_key = ENV['QDRANT_API_KEY']
|
|
13
|
+
# config.host = 'https://your-cluster.qdrant.io'
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# client = Vectra::Client.new
|
|
17
|
+
# client.upsert(index: 'my-collection', vectors: [...])
|
|
18
|
+
#
|
|
19
|
+
# rubocop:disable Metrics/ClassLength
|
|
9
20
|
class Qdrant < Base
|
|
21
|
+
# @see Base#provider_name
|
|
10
22
|
def provider_name
|
|
11
23
|
:qdrant
|
|
12
24
|
end
|
|
13
25
|
|
|
26
|
+
# @see Base#upsert
|
|
14
27
|
def upsert(index:, vectors:, namespace: nil)
|
|
15
|
-
|
|
28
|
+
normalized = normalize_vectors(vectors)
|
|
29
|
+
|
|
30
|
+
points = normalized.map do |vec|
|
|
31
|
+
point = {
|
|
32
|
+
id: generate_point_id(vec[:id]),
|
|
33
|
+
vector: vec[:values]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
payload = vec[:metadata] || {}
|
|
37
|
+
payload["_namespace"] = namespace if namespace
|
|
38
|
+
point[:payload] = payload unless payload.empty?
|
|
39
|
+
|
|
40
|
+
point
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
body = {
|
|
44
|
+
points: points
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
response = with_error_handling { connection.put("/collections/#{index}/points", body) }
|
|
48
|
+
|
|
49
|
+
if response.success?
|
|
50
|
+
log_debug("Upserted #{normalized.size} vectors to #{index}")
|
|
51
|
+
{ upserted_count: normalized.size }
|
|
52
|
+
else
|
|
53
|
+
handle_error(response)
|
|
54
|
+
end
|
|
16
55
|
end
|
|
17
56
|
|
|
57
|
+
# @see Base#query
|
|
18
58
|
def query(index:, vector:, top_k: 10, namespace: nil, filter: nil,
|
|
19
59
|
include_values: false, include_metadata: true)
|
|
20
|
-
|
|
60
|
+
body = {
|
|
61
|
+
vector: vector.map(&:to_f),
|
|
62
|
+
limit: top_k,
|
|
63
|
+
with_vector: include_values,
|
|
64
|
+
with_payload: include_metadata
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Build filter with namespace if provided
|
|
68
|
+
qdrant_filter = build_filter(filter, namespace)
|
|
69
|
+
body[:filter] = qdrant_filter if qdrant_filter
|
|
70
|
+
|
|
71
|
+
response = with_error_handling { connection.post("/collections/#{index}/points/search", body) }
|
|
72
|
+
|
|
73
|
+
if response.success?
|
|
74
|
+
matches = transform_search_results(response.body["result"] || [])
|
|
75
|
+
log_debug("Query returned #{matches.size} results")
|
|
76
|
+
|
|
77
|
+
QueryResult.from_response(
|
|
78
|
+
matches: matches,
|
|
79
|
+
namespace: namespace
|
|
80
|
+
)
|
|
81
|
+
else
|
|
82
|
+
handle_error(response)
|
|
83
|
+
end
|
|
21
84
|
end
|
|
22
85
|
|
|
23
|
-
|
|
24
|
-
|
|
86
|
+
# @see Base#fetch
|
|
87
|
+
def fetch(index:, ids:, namespace: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
88
|
+
point_ids = ids.map { |id| generate_point_id(id) }
|
|
89
|
+
|
|
90
|
+
body = {
|
|
91
|
+
ids: point_ids,
|
|
92
|
+
with_vector: true,
|
|
93
|
+
with_payload: true
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
response = with_error_handling { connection.post("/collections/#{index}/points", body) }
|
|
97
|
+
|
|
98
|
+
if response.success?
|
|
99
|
+
vectors = {}
|
|
100
|
+
(response.body["result"] || []).each do |point|
|
|
101
|
+
original_id = extract_original_id(point["id"])
|
|
102
|
+
vectors[original_id] = Vector.new(
|
|
103
|
+
id: original_id,
|
|
104
|
+
values: point["vector"],
|
|
105
|
+
metadata: clean_payload(point["payload"])
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
vectors
|
|
109
|
+
else
|
|
110
|
+
handle_error(response)
|
|
111
|
+
end
|
|
25
112
|
end
|
|
26
113
|
|
|
27
|
-
|
|
28
|
-
|
|
114
|
+
# @see Base#update
|
|
115
|
+
def update(index:, id:, metadata: nil, values: nil, namespace: nil)
|
|
116
|
+
point_id = generate_point_id(id)
|
|
117
|
+
|
|
118
|
+
# Update payload (metadata) if provided
|
|
119
|
+
if metadata
|
|
120
|
+
payload = metadata.dup
|
|
121
|
+
payload["_namespace"] = namespace if namespace
|
|
122
|
+
|
|
123
|
+
payload_body = {
|
|
124
|
+
points: [point_id],
|
|
125
|
+
payload: payload
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
response = with_error_handling { connection.post("/collections/#{index}/points/payload", payload_body) }
|
|
129
|
+
handle_error(response) unless response.success?
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Update vector if provided
|
|
133
|
+
if values
|
|
134
|
+
vector_body = {
|
|
135
|
+
points: [
|
|
136
|
+
{
|
|
137
|
+
id: point_id,
|
|
138
|
+
vector: values.map(&:to_f)
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
response = with_error_handling { connection.put("/collections/#{index}/points", vector_body) }
|
|
144
|
+
handle_error(response) unless response.success?
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
log_debug("Updated vector #{id}")
|
|
148
|
+
{ updated: true }
|
|
29
149
|
end
|
|
30
150
|
|
|
151
|
+
# @see Base#delete
|
|
31
152
|
def delete(index:, ids: nil, namespace: nil, filter: nil, delete_all: false)
|
|
32
|
-
|
|
153
|
+
if delete_all
|
|
154
|
+
# Delete all points in collection
|
|
155
|
+
body = { filter: {} }
|
|
156
|
+
elsif ids
|
|
157
|
+
# Delete by IDs
|
|
158
|
+
point_ids = ids.map { |id| generate_point_id(id) }
|
|
159
|
+
body = { points: point_ids }
|
|
160
|
+
elsif filter || namespace
|
|
161
|
+
# Delete by filter
|
|
162
|
+
body = { filter: build_filter(filter, namespace) }
|
|
163
|
+
else
|
|
164
|
+
raise ValidationError, "Must specify ids, filter, or delete_all"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
response = with_error_handling { connection.post("/collections/#{index}/points/delete", body) }
|
|
168
|
+
|
|
169
|
+
if response.success?
|
|
170
|
+
log_debug("Deleted vectors from #{index}")
|
|
171
|
+
{ deleted: true }
|
|
172
|
+
else
|
|
173
|
+
handle_error(response)
|
|
174
|
+
end
|
|
33
175
|
end
|
|
34
176
|
|
|
177
|
+
# @see Base#list_indexes
|
|
35
178
|
def list_indexes
|
|
36
|
-
|
|
179
|
+
response = with_error_handling { connection.get("/collections") }
|
|
180
|
+
|
|
181
|
+
if response.success?
|
|
182
|
+
(response.body["result"]&.dig("collections") || []).map do |col|
|
|
183
|
+
# Get collection info for each
|
|
184
|
+
info = describe_index(index: col["name"])
|
|
185
|
+
info
|
|
186
|
+
rescue StandardError
|
|
187
|
+
{ name: col["name"], status: "unknown" }
|
|
188
|
+
end
|
|
189
|
+
else
|
|
190
|
+
handle_error(response)
|
|
191
|
+
end
|
|
37
192
|
end
|
|
38
193
|
|
|
194
|
+
# @see Base#describe_index
|
|
195
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
39
196
|
def describe_index(index:)
|
|
40
|
-
|
|
197
|
+
response = with_error_handling { connection.get("/collections/#{index}") }
|
|
198
|
+
|
|
199
|
+
if response.success?
|
|
200
|
+
result = response.body["result"]
|
|
201
|
+
config = result["config"]
|
|
202
|
+
params = config&.dig("params") || {}
|
|
203
|
+
vectors_config = params["vectors"] || {}
|
|
204
|
+
|
|
205
|
+
# Handle both named and unnamed vector configs
|
|
206
|
+
dimension = if vectors_config.is_a?(Hash) && vectors_config["size"]
|
|
207
|
+
vectors_config["size"]
|
|
208
|
+
elsif vectors_config.is_a?(Hash)
|
|
209
|
+
vectors_config.values.first&.dig("size")
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
distance = vectors_config["distance"] || vectors_config.values.first&.dig("distance")
|
|
213
|
+
|
|
214
|
+
{
|
|
215
|
+
name: index,
|
|
216
|
+
dimension: dimension,
|
|
217
|
+
metric: distance_to_metric(distance),
|
|
218
|
+
status: result["status"],
|
|
219
|
+
vectors_count: result["vectors_count"],
|
|
220
|
+
points_count: result["points_count"]
|
|
221
|
+
}
|
|
222
|
+
else
|
|
223
|
+
handle_error(response)
|
|
224
|
+
end
|
|
41
225
|
end
|
|
226
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
42
227
|
|
|
228
|
+
# @see Base#stats
|
|
43
229
|
def stats(index:, namespace: nil)
|
|
44
|
-
|
|
230
|
+
info = describe_index(index: index)
|
|
231
|
+
|
|
232
|
+
{
|
|
233
|
+
total_vector_count: info[:points_count] || info[:vectors_count] || 0,
|
|
234
|
+
dimension: info[:dimension],
|
|
235
|
+
status: info[:status],
|
|
236
|
+
namespaces: namespace ? { namespace => { vector_count: 0 } } : {}
|
|
237
|
+
}
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Create a new collection
|
|
241
|
+
#
|
|
242
|
+
# @param name [String] collection name
|
|
243
|
+
# @param dimension [Integer] vector dimension
|
|
244
|
+
# @param metric [String] similarity metric (cosine, euclidean, dot_product)
|
|
245
|
+
# @param on_disk [Boolean] store vectors on disk
|
|
246
|
+
# @return [Hash] created collection info
|
|
247
|
+
def create_index(name:, dimension:, metric: "cosine", on_disk: false)
|
|
248
|
+
body = {
|
|
249
|
+
vectors: {
|
|
250
|
+
size: dimension,
|
|
251
|
+
distance: metric_to_distance(metric),
|
|
252
|
+
on_disk: on_disk
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
response = with_error_handling { connection.put("/collections/#{name}", body) }
|
|
257
|
+
|
|
258
|
+
if response.success?
|
|
259
|
+
log_debug("Created collection #{name}")
|
|
260
|
+
describe_index(index: name)
|
|
261
|
+
else
|
|
262
|
+
handle_error(response)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Delete a collection
|
|
267
|
+
#
|
|
268
|
+
# @param name [String] collection name
|
|
269
|
+
# @return [Hash] deletion result
|
|
270
|
+
def delete_index(name:)
|
|
271
|
+
response = with_error_handling { connection.delete("/collections/#{name}") }
|
|
272
|
+
|
|
273
|
+
if response.success?
|
|
274
|
+
log_debug("Deleted collection #{name}")
|
|
275
|
+
{ deleted: true }
|
|
276
|
+
else
|
|
277
|
+
handle_error(response)
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
private
|
|
282
|
+
|
|
283
|
+
def validate_config!
|
|
284
|
+
super
|
|
285
|
+
raise ConfigurationError, "Host must be configured for Qdrant" if config.host.nil? || config.host.empty?
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def connection
|
|
289
|
+
@connection ||= build_connection(
|
|
290
|
+
config.host,
|
|
291
|
+
auth_headers
|
|
292
|
+
)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Wrap HTTP calls to handle Faraday::RetriableResponse
|
|
296
|
+
def with_error_handling
|
|
297
|
+
yield
|
|
298
|
+
rescue Faraday::RetriableResponse => e
|
|
299
|
+
handle_retriable_response(e)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def auth_headers
|
|
303
|
+
headers = {}
|
|
304
|
+
headers["api-key"] = config.api_key if config.api_key && !config.api_key.empty?
|
|
305
|
+
headers
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Generate a Qdrant point ID from string ID
|
|
309
|
+
# Qdrant supports both integer and UUID point IDs
|
|
310
|
+
# We use a hash to convert arbitrary strings to integers
|
|
311
|
+
def generate_point_id(id)
|
|
312
|
+
# If it's already a valid integer or UUID, use it
|
|
313
|
+
return id.to_i if id.to_s.match?(/^\d+$/)
|
|
314
|
+
return id if uuid?(id)
|
|
315
|
+
|
|
316
|
+
# Otherwise, store original ID in payload and use hash
|
|
317
|
+
id.to_s.hash.abs
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def uuid?(str)
|
|
321
|
+
str.to_s.match?(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def extract_original_id(point_id)
|
|
325
|
+
point_id.to_s
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Build Qdrant filter from Vectra filter and namespace
|
|
329
|
+
def build_filter(filter, namespace)
|
|
330
|
+
conditions = []
|
|
331
|
+
|
|
332
|
+
# Add namespace filter
|
|
333
|
+
if namespace
|
|
334
|
+
conditions << {
|
|
335
|
+
key: "_namespace",
|
|
336
|
+
match: { value: namespace }
|
|
337
|
+
}
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Add metadata filters
|
|
341
|
+
if filter.is_a?(Hash)
|
|
342
|
+
filter.each do |key, value|
|
|
343
|
+
conditions << build_condition(key.to_s, value)
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
return nil if conditions.empty?
|
|
348
|
+
|
|
349
|
+
{ must: conditions }
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def build_condition(key, value)
|
|
353
|
+
case value
|
|
354
|
+
when Hash
|
|
355
|
+
# Handle operators like { "$gt" => 5 }
|
|
356
|
+
build_operator_condition(key, value)
|
|
357
|
+
when Array
|
|
358
|
+
# IN operator
|
|
359
|
+
{ key: key, match: { any: value } }
|
|
360
|
+
else
|
|
361
|
+
# Exact match
|
|
362
|
+
{ key: key, match: { value: value } }
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def build_operator_condition(key, operator_hash)
|
|
367
|
+
operator, val = operator_hash.first
|
|
368
|
+
|
|
369
|
+
case operator.to_s
|
|
370
|
+
when "$ne"
|
|
371
|
+
{ key: key, match: { except: [val] } }
|
|
372
|
+
when "$gt"
|
|
373
|
+
{ key: key, range: { gt: val } }
|
|
374
|
+
when "$gte"
|
|
375
|
+
{ key: key, range: { gte: val } }
|
|
376
|
+
when "$lt"
|
|
377
|
+
{ key: key, range: { lt: val } }
|
|
378
|
+
when "$lte"
|
|
379
|
+
{ key: key, range: { lte: val } }
|
|
380
|
+
when "$in"
|
|
381
|
+
{ key: key, match: { any: val } }
|
|
382
|
+
when "$nin"
|
|
383
|
+
{ key: key, match: { except: val } }
|
|
384
|
+
else # $eq or unknown operator - exact match
|
|
385
|
+
{ key: key, match: { value: val } }
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def transform_search_results(results)
|
|
390
|
+
results.map do |result|
|
|
391
|
+
{
|
|
392
|
+
id: extract_original_id(result["id"]),
|
|
393
|
+
score: result["score"],
|
|
394
|
+
values: result["vector"],
|
|
395
|
+
metadata: clean_payload(result["payload"])
|
|
396
|
+
}
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# Remove internal fields from payload
|
|
401
|
+
def clean_payload(payload)
|
|
402
|
+
return {} unless payload
|
|
403
|
+
|
|
404
|
+
payload.reject { |k, _| k.to_s.start_with?("_") }
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# Convert Vectra metric to Qdrant distance
|
|
408
|
+
def metric_to_distance(metric)
|
|
409
|
+
case metric.to_s.downcase
|
|
410
|
+
when "euclidean", "l2"
|
|
411
|
+
"Euclid"
|
|
412
|
+
when "dot_product", "dotproduct", "inner_product"
|
|
413
|
+
"Dot"
|
|
414
|
+
else # cosine or unknown - default to Cosine
|
|
415
|
+
"Cosine"
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# Convert Qdrant distance to Vectra metric
|
|
420
|
+
def distance_to_metric(distance)
|
|
421
|
+
case distance.to_s
|
|
422
|
+
when "Cosine"
|
|
423
|
+
"cosine"
|
|
424
|
+
when "Euclid"
|
|
425
|
+
"euclidean"
|
|
426
|
+
when "Dot"
|
|
427
|
+
"dot_product"
|
|
428
|
+
else
|
|
429
|
+
distance.to_s.downcase
|
|
430
|
+
end
|
|
45
431
|
end
|
|
46
432
|
end
|
|
433
|
+
# rubocop:enable Metrics/ClassLength
|
|
47
434
|
end
|
|
48
435
|
end
|
data/lib/vectra/version.rb
CHANGED
data/lib/vectra.rb
CHANGED
|
@@ -90,11 +90,18 @@ module Vectra
|
|
|
90
90
|
|
|
91
91
|
# Shortcut to create a Qdrant client
|
|
92
92
|
#
|
|
93
|
-
# @param api_key [String] Qdrant API key
|
|
94
93
|
# @param host [String] Qdrant host URL
|
|
94
|
+
# @param api_key [String, nil] Qdrant API key (optional for local instances)
|
|
95
95
|
# @param options [Hash] additional options
|
|
96
96
|
# @return [Client]
|
|
97
|
-
|
|
97
|
+
#
|
|
98
|
+
# @example Local Qdrant (no API key)
|
|
99
|
+
# Vectra.qdrant(host: "http://localhost:6333")
|
|
100
|
+
#
|
|
101
|
+
# @example Qdrant Cloud
|
|
102
|
+
# Vectra.qdrant(host: "https://your-cluster.qdrant.io", api_key: ENV["QDRANT_API_KEY"])
|
|
103
|
+
#
|
|
104
|
+
def qdrant(host:, api_key: nil, **options)
|
|
98
105
|
Client.new(
|
|
99
106
|
provider: :qdrant,
|
|
100
107
|
api_key: api_key,
|
data/netlify.toml
ADDED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vectra-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mijo Kristo
|
|
@@ -55,16 +55,16 @@ dependencies:
|
|
|
55
55
|
name: sqlite3
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
|
58
|
-
- - "
|
|
58
|
+
- - ">="
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '1
|
|
60
|
+
version: '2.1'
|
|
61
61
|
type: :development
|
|
62
62
|
prerelease: false
|
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
64
|
requirements:
|
|
65
|
-
- - "
|
|
65
|
+
- - ">="
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: '1
|
|
67
|
+
version: '2.1'
|
|
68
68
|
- !ruby/object:Gem::Dependency
|
|
69
69
|
name: pg
|
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -207,16 +207,49 @@ files:
|
|
|
207
207
|
- CHANGELOG.md
|
|
208
208
|
- CODE_OF_CONDUCT.md
|
|
209
209
|
- CONTRIBUTING.md
|
|
210
|
-
- IMPLEMENTATION_GUIDE.md
|
|
211
210
|
- LICENSE
|
|
212
|
-
- NEW_FEATURES_v0.2.0.md
|
|
213
211
|
- README.md
|
|
214
|
-
- RELEASE_CHECKLIST_v0.2.0.md
|
|
215
212
|
- Rakefile
|
|
216
213
|
- SECURITY.md
|
|
217
|
-
- USAGE_EXAMPLES.md
|
|
218
214
|
- benchmarks/batch_operations_benchmark.rb
|
|
219
215
|
- benchmarks/connection_pooling_benchmark.rb
|
|
216
|
+
- docs/Gemfile
|
|
217
|
+
- docs/_config.yml
|
|
218
|
+
- docs/_layouts/default.html
|
|
219
|
+
- docs/_layouts/home.html
|
|
220
|
+
- docs/_layouts/page.html
|
|
221
|
+
- docs/_site/api/overview/index.html
|
|
222
|
+
- docs/_site/assets/main.css
|
|
223
|
+
- docs/_site/assets/main.css.map
|
|
224
|
+
- docs/_site/assets/minima-social-icons.svg
|
|
225
|
+
- docs/_site/assets/style.css
|
|
226
|
+
- docs/_site/community/contributing/index.html
|
|
227
|
+
- docs/_site/examples/basic-usage/index.html
|
|
228
|
+
- docs/_site/examples/index.html
|
|
229
|
+
- docs/_site/feed.xml
|
|
230
|
+
- docs/_site/guides/getting-started/index.html
|
|
231
|
+
- docs/_site/guides/installation/index.html
|
|
232
|
+
- docs/_site/index.html
|
|
233
|
+
- docs/_site/providers/index.html
|
|
234
|
+
- docs/_site/providers/pgvector/index.html
|
|
235
|
+
- docs/_site/providers/pinecone/index.html
|
|
236
|
+
- docs/_site/providers/qdrant/index.html
|
|
237
|
+
- docs/_site/providers/weaviate/index.html
|
|
238
|
+
- docs/_site/robots.txt
|
|
239
|
+
- docs/_site/sitemap.xml
|
|
240
|
+
- docs/api/overview.md
|
|
241
|
+
- docs/assets/style.css
|
|
242
|
+
- docs/community/contributing.md
|
|
243
|
+
- docs/examples/basic-usage.md
|
|
244
|
+
- docs/examples/index.md
|
|
245
|
+
- docs/guides/getting-started.md
|
|
246
|
+
- docs/guides/installation.md
|
|
247
|
+
- docs/index.md
|
|
248
|
+
- docs/providers/index.md
|
|
249
|
+
- docs/providers/pgvector.md
|
|
250
|
+
- docs/providers/pinecone.md
|
|
251
|
+
- docs/providers/qdrant.md
|
|
252
|
+
- docs/providers/weaviate.md
|
|
220
253
|
- examples/active_record_demo.rb
|
|
221
254
|
- examples/instrumentation_demo.rb
|
|
222
255
|
- lib/generators/vectra/install_generator.rb
|
|
@@ -242,6 +275,7 @@ files:
|
|
|
242
275
|
- lib/vectra/retry.rb
|
|
243
276
|
- lib/vectra/vector.rb
|
|
244
277
|
- lib/vectra/version.rb
|
|
278
|
+
- netlify.toml
|
|
245
279
|
homepage: https://github.com/stokry/vectra
|
|
246
280
|
licenses:
|
|
247
281
|
- MIT
|