vector-vault 0.2.4__tar.gz → 0.2.7__tar.gz
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.
- {vector_vault-0.2.4 → vector_vault-0.2.7}/PKG-INFO +1 -1
- {vector_vault-0.2.4 → vector_vault-0.2.7}/setup.py +1 -1
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vector_vault.egg-info/PKG-INFO +1 -1
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vector_vault.egg-info/SOURCES.txt +1 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vectorvault/cloudmanager.py +13 -14
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vectorvault/creds.py +2 -2
- vector_vault-0.2.7/vectorvault/itemize.py +63 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vectorvault/vault.py +19 -74
- {vector_vault-0.2.4 → vector_vault-0.2.7}/LICENSE +0 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/README.md +0 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/setup.cfg +0 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vector_vault.egg-info/dependency_links.txt +0 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vector_vault.egg-info/requires.txt +0 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vector_vault.egg-info/top_level.txt +0 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vectorvault/__init__.py +0 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vectorvault/closedai.py +0 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vectorvault/download.py +0 -0
- {vector_vault-0.2.4 → vector_vault-0.2.7}/vectorvault/wrap.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vector_vault
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: VectorVault: Simplified vector database management in the cloud for machine learning and generative ai workflows
|
|
5
5
|
Home-page: https://github.com/John-Rood/VectorVault
|
|
6
6
|
Author: VectorVault.io
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vector-vault
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: VectorVault: Simplified vector database management in the cloud for machine learning and generative ai workflows
|
|
5
5
|
Home-page: https://github.com/John-Rood/VectorVault
|
|
6
6
|
Author: VectorVault.io
|
|
@@ -17,6 +17,7 @@ import tempfile
|
|
|
17
17
|
import os
|
|
18
18
|
import json
|
|
19
19
|
from .creds import CustomCredentials
|
|
20
|
+
from .itemize import name
|
|
20
21
|
from google.cloud import storage
|
|
21
22
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
22
23
|
|
|
@@ -26,48 +27,46 @@ class CloudManager:
|
|
|
26
27
|
self.user = user
|
|
27
28
|
self.api = api_key
|
|
28
29
|
self.vault = vault
|
|
29
|
-
|
|
30
|
-
# Create the OAuth credentials
|
|
30
|
+
# Creates the credentials
|
|
31
31
|
credentials = CustomCredentials(self.user, self.api)
|
|
32
|
-
|
|
33
|
-
# Instantiates a client with the OAuth2 credentials
|
|
32
|
+
# Instantiates the client
|
|
34
33
|
self.storage_client = storage.Client(project='vectorvault-361ab', credentials=credentials)
|
|
35
|
-
self.
|
|
34
|
+
self.cloud = self.storage_client.bucket(self.user)
|
|
36
35
|
print(f'Connected to Vault: {self.vault}')
|
|
37
36
|
|
|
38
37
|
def vault_exists(self, vault_name):
|
|
39
|
-
return storage.Blob(bucket=self.
|
|
38
|
+
return storage.Blob(bucket=self.cloud, name=vault_name).exists(self.storage_client)
|
|
40
39
|
|
|
41
40
|
def upload_to_cloud(self, vault_name, content):
|
|
42
|
-
blob = self.
|
|
41
|
+
blob = self.cloud.blob(vault_name)
|
|
43
42
|
blob.upload_from_string(content)
|
|
44
43
|
|
|
45
44
|
def download_text_from_cloud(self, vault_name):
|
|
46
|
-
blob = self.
|
|
45
|
+
blob = self.cloud.blob(vault_name)
|
|
47
46
|
return blob.download_as_text()
|
|
48
47
|
|
|
49
48
|
def upload_temp_file(self, temp_file_path, vault_name):
|
|
50
|
-
blob = self.
|
|
49
|
+
blob = self.cloud.blob(vault_name)
|
|
51
50
|
blob.upload_from_filename(temp_file_path)
|
|
52
51
|
os.remove(temp_file_path)
|
|
53
52
|
|
|
54
53
|
def download_to_temp_file(self, vault_name):
|
|
55
54
|
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
|
56
|
-
blob = self.
|
|
55
|
+
blob = self.cloud.blob(vault_name)
|
|
57
56
|
blob.download_to_filename(temp_file.name)
|
|
58
57
|
return temp_file.name
|
|
59
58
|
|
|
60
59
|
def upload(self, item, text, meta):
|
|
61
60
|
with ThreadPoolExecutor() as executor:
|
|
62
|
-
executor.submit(self.upload_to_cloud,
|
|
63
|
-
executor.submit(self.upload_to_cloud,
|
|
61
|
+
executor.submit(self.upload_to_cloud, name(self.vault, item, item=True), text)
|
|
62
|
+
executor.submit(self.upload_to_cloud, name(self.vault, item, meta=True), json.dumps(meta))
|
|
64
63
|
|
|
65
64
|
def delete_blob(self, blob):
|
|
66
65
|
blob.delete()
|
|
67
66
|
|
|
68
67
|
def delete(self):
|
|
69
68
|
# Get all objects
|
|
70
|
-
blobs = self.
|
|
69
|
+
blobs = self.cloud.list_blobs(prefix=self.vault)
|
|
71
70
|
|
|
72
71
|
# Delete each object concurrently
|
|
73
72
|
with ThreadPoolExecutor() as executor:
|
|
@@ -81,7 +80,7 @@ class CloudManager:
|
|
|
81
80
|
|
|
82
81
|
def get_vaults(self, vault: str = None):
|
|
83
82
|
vault = self.vault if vault is None else vault
|
|
84
|
-
blobs = self.
|
|
83
|
+
blobs = self.cloud.list_blobs(prefix=f'{vault}')
|
|
85
84
|
|
|
86
85
|
directories = set()
|
|
87
86
|
for blob in blobs:
|
|
@@ -34,7 +34,7 @@ class CustomCredentials(Credentials):
|
|
|
34
34
|
return False
|
|
35
35
|
return datetime.datetime.now() < self.expiry
|
|
36
36
|
|
|
37
|
-
def refresh(self
|
|
37
|
+
def refresh(self):
|
|
38
38
|
if not self.valid:
|
|
39
39
|
data = {
|
|
40
40
|
"user_id": self.user,
|
|
@@ -46,7 +46,7 @@ class CustomCredentials(Credentials):
|
|
|
46
46
|
self.token = response_data['access_token']
|
|
47
47
|
self.expiry = datetime.datetime.fromisoformat(response_data['expiry'])
|
|
48
48
|
|
|
49
|
-
def before_request(self,
|
|
49
|
+
def before_request(self, headers):
|
|
50
50
|
self.apply(headers)
|
|
51
51
|
|
|
52
52
|
def __getstate__(self):
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from annoy import AnnoyIndex
|
|
3
|
+
|
|
4
|
+
def itemize(vault, x, meta=None, text=None, name=None):
|
|
5
|
+
meta = {} if meta is None else meta
|
|
6
|
+
|
|
7
|
+
if 'name' not in meta and name is None:
|
|
8
|
+
name = f'{vault}-{x}'
|
|
9
|
+
elif name is not None:
|
|
10
|
+
name = __name__
|
|
11
|
+
metaize(meta, name, x)
|
|
12
|
+
return package(text, meta)
|
|
13
|
+
|
|
14
|
+
def metaize(meta, name, x):
|
|
15
|
+
meta['name'] = name
|
|
16
|
+
meta['item_id'] = x
|
|
17
|
+
if 'created_at' not in meta:
|
|
18
|
+
meta['created_at'] = datetime.datetime.utcnow().isoformat()
|
|
19
|
+
if 'updated_at' not in meta:
|
|
20
|
+
meta['updated_at'] = datetime.datetime.utcnow().isoformat()
|
|
21
|
+
|
|
22
|
+
def package(text, meta):
|
|
23
|
+
item = {
|
|
24
|
+
"text": text,
|
|
25
|
+
"meta": meta
|
|
26
|
+
}
|
|
27
|
+
return item
|
|
28
|
+
|
|
29
|
+
def build_base_path(v, x):
|
|
30
|
+
return f'{v}/{x}'
|
|
31
|
+
|
|
32
|
+
def append_path_suffix(base_path, is_item, is_meta):
|
|
33
|
+
if is_item:
|
|
34
|
+
suffix = 'item'
|
|
35
|
+
elif is_meta:
|
|
36
|
+
suffix = 'meta'
|
|
37
|
+
else:
|
|
38
|
+
suffix = ''
|
|
39
|
+
return f'{base_path}/{suffix}'
|
|
40
|
+
|
|
41
|
+
def name(v, x, item=False, meta=False):
|
|
42
|
+
base_path = build_base_path(v, x)
|
|
43
|
+
final_path = append_path_suffix(base_path, item, meta)
|
|
44
|
+
return final_path
|
|
45
|
+
|
|
46
|
+
def name_vecs(vault):
|
|
47
|
+
return f'{vault}.ann'
|
|
48
|
+
|
|
49
|
+
def get_vectors(dims):
|
|
50
|
+
return AnnoyIndex(dims, 'angular')
|
|
51
|
+
|
|
52
|
+
def get_item(item):
|
|
53
|
+
item_id = item["meta"]["item_id"]
|
|
54
|
+
item_text = item["text"]
|
|
55
|
+
item_meta = item["meta"]
|
|
56
|
+
return item_text, item_id, item_meta
|
|
57
|
+
|
|
58
|
+
def build_return(results, item_data, meta):
|
|
59
|
+
result = {
|
|
60
|
+
"data": item_data,
|
|
61
|
+
"metadata": meta
|
|
62
|
+
}
|
|
63
|
+
results.append(result)
|
|
@@ -16,21 +16,20 @@
|
|
|
16
16
|
import numpy as np
|
|
17
17
|
import tempfile
|
|
18
18
|
import os
|
|
19
|
-
import datetime
|
|
20
19
|
import time
|
|
21
20
|
import json
|
|
22
21
|
import re
|
|
23
22
|
import openai
|
|
24
|
-
from annoy import AnnoyIndex
|
|
25
23
|
from concurrent.futures import ThreadPoolExecutor
|
|
26
24
|
from .cloudmanager import CloudManager
|
|
27
25
|
from .closedai import ClosedAI
|
|
26
|
+
from .itemize import itemize, name, name_vecs, get_item, build_return, get_vectors
|
|
28
27
|
|
|
29
28
|
|
|
30
29
|
class Vault:
|
|
31
30
|
def __init__(self, user: str, api_key: str, vault: str = None, dims: int = 1536, verbose: bool = False):
|
|
32
31
|
self.vault = vault.strip() if vault else 'home'
|
|
33
|
-
self.vectors =
|
|
32
|
+
self.vectors = get_vectors(dims)
|
|
34
33
|
self.dims = dims
|
|
35
34
|
self.cloud_manager = CloudManager(user, api_key, self.vault)
|
|
36
35
|
self.x = 0
|
|
@@ -46,15 +45,14 @@ class Vault:
|
|
|
46
45
|
|
|
47
46
|
def check_index(self):
|
|
48
47
|
start_time = time.time()
|
|
49
|
-
if self.cloud_manager.vault_exists(
|
|
50
|
-
print('vault exists')
|
|
48
|
+
if self.cloud_manager.vault_exists(name_vecs(self.vault)):
|
|
51
49
|
self.load_vectors()
|
|
52
50
|
num_existing_items = self.vectors.get_n_items()
|
|
53
|
-
new_index =
|
|
51
|
+
new_index = get_vectors(self.dims)
|
|
54
52
|
for i in range(num_existing_items):
|
|
55
53
|
vector = self.vectors.get_item_vector(i)
|
|
56
54
|
new_index.add_item(i, vector)
|
|
57
|
-
|
|
55
|
+
self.x = i + 1
|
|
58
56
|
self.vectors = new_index
|
|
59
57
|
else:
|
|
60
58
|
pass
|
|
@@ -67,7 +65,7 @@ class Vault:
|
|
|
67
65
|
def load_vectors(self):
|
|
68
66
|
start_time = time.time()
|
|
69
67
|
# Download the .ann file from google cloud storage to a temporary file
|
|
70
|
-
temp_file_path = self.cloud_manager.download_to_temp_file(
|
|
68
|
+
temp_file_path = self.cloud_manager.download_to_temp_file(name_vecs(self.vault))
|
|
71
69
|
|
|
72
70
|
# Load the AnnoyIndex object from the temporary file, then delete the temp file
|
|
73
71
|
self.vectors.load(temp_file_path)
|
|
@@ -78,7 +76,7 @@ class Vault:
|
|
|
78
76
|
|
|
79
77
|
def get_vaults(self, vault: str = None):
|
|
80
78
|
vault = self.vault if vault is None else vault
|
|
81
|
-
return self.cloud_manager.get_vaults(vault
|
|
79
|
+
return self.cloud_manager.get_vaults(vault)
|
|
82
80
|
|
|
83
81
|
|
|
84
82
|
def get_total_vectors(self):
|
|
@@ -91,12 +89,12 @@ class Vault:
|
|
|
91
89
|
|
|
92
90
|
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
|
93
91
|
self.vectors.save(temp_file.name)
|
|
94
|
-
self.cloud_manager.upload_temp_file(temp_file.name,
|
|
92
|
+
self.cloud_manager.upload_temp_file(temp_file.name, name_vecs(self.vault))
|
|
95
93
|
|
|
96
94
|
total_saved_items = 0
|
|
97
95
|
for item in self.items:
|
|
98
|
-
item_id = item
|
|
99
|
-
self.cloud_manager.upload(item_id,
|
|
96
|
+
item_text, item_id, item_meta = get_item(item)
|
|
97
|
+
self.cloud_manager.upload(item_id, item_text, item_meta)
|
|
100
98
|
total_saved_items += 1
|
|
101
99
|
|
|
102
100
|
self.items.clear()
|
|
@@ -110,7 +108,7 @@ class Vault:
|
|
|
110
108
|
if self.verbose == True:
|
|
111
109
|
print('Deleting started. Note: this can take a while for large datasets')
|
|
112
110
|
# Clear the local vector data
|
|
113
|
-
self.vectors =
|
|
111
|
+
self.vectors = get_vectors(self.dims)
|
|
114
112
|
self.items.clear()
|
|
115
113
|
self.x = 0
|
|
116
114
|
self.cloud_manager.delete()
|
|
@@ -157,26 +155,15 @@ class Vault:
|
|
|
157
155
|
self.load_vectors()
|
|
158
156
|
start_time = time.time()
|
|
159
157
|
|
|
160
|
-
# Create an empty list to store the results
|
|
161
158
|
results = []
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
for index in indexes:
|
|
159
|
+
vecs = self.vectors.get_nns_by_vector(vector, n)
|
|
160
|
+
for vec in vecs:
|
|
165
161
|
# Retrieve the item
|
|
166
|
-
item_data = self.cloud_manager.download_text_from_cloud(
|
|
167
|
-
|
|
162
|
+
item_data = self.cloud_manager.download_text_from_cloud(name(self.vault, vec, item=True))
|
|
168
163
|
# Retrieve the metadata
|
|
169
|
-
meta_data = self.cloud_manager.download_text_from_cloud(
|
|
164
|
+
meta_data = self.cloud_manager.download_text_from_cloud(name(self.vault, vec, meta=True))
|
|
170
165
|
meta = json.loads(meta_data)
|
|
171
|
-
|
|
172
|
-
# Create a dictionary with data and metadata
|
|
173
|
-
result = {
|
|
174
|
-
"data": item_data,
|
|
175
|
-
"metadata": meta
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
# Append the result to the list
|
|
179
|
-
results.append(result)
|
|
166
|
+
build_return(results, item_data, meta)
|
|
180
167
|
|
|
181
168
|
# Create a return dictionary
|
|
182
169
|
return_dict = {
|
|
@@ -203,29 +190,8 @@ class Vault:
|
|
|
203
190
|
self.check_index()
|
|
204
191
|
else:
|
|
205
192
|
pass
|
|
206
|
-
|
|
207
|
-
# set value if none exist
|
|
208
|
-
meta = {} if meta is None else meta
|
|
209
|
-
|
|
210
|
-
if 'name' not in meta and name is None:
|
|
211
|
-
name = f'{self.vault}-{self.x}'
|
|
212
|
-
elif name is not None:
|
|
213
|
-
name = name
|
|
214
|
-
meta['name'] = name
|
|
215
|
-
meta['item_id'] = self.x # Store the item index in the metadata
|
|
216
|
-
|
|
217
|
-
if 'created_at' not in meta:
|
|
218
|
-
meta['created_at'] = datetime.datetime.utcnow().isoformat()
|
|
219
|
-
if 'updated_at' not in meta:
|
|
220
|
-
meta['updated_at'] = datetime.datetime.utcnow().isoformat()
|
|
221
|
-
|
|
222
|
-
# Add item and its metadata to the items list
|
|
223
|
-
item = {
|
|
224
|
-
"text": text,
|
|
225
|
-
"meta": meta
|
|
226
|
-
}
|
|
227
|
-
self.items.append(item)
|
|
228
193
|
|
|
194
|
+
self.items.append(itemize(self.vault, self.x, meta, text, name))
|
|
229
195
|
self.x += 1
|
|
230
196
|
|
|
231
197
|
|
|
@@ -243,7 +209,7 @@ class Vault:
|
|
|
243
209
|
texts = [text]
|
|
244
210
|
|
|
245
211
|
for text in texts:
|
|
246
|
-
self.add_item(text)
|
|
212
|
+
self.add_item(text, meta, name)
|
|
247
213
|
|
|
248
214
|
|
|
249
215
|
def add_item_with_vector(self, text: str, vector: list, meta: dict = None, name: str = None):
|
|
@@ -260,30 +226,9 @@ class Vault:
|
|
|
260
226
|
if len(text) > 36000:
|
|
261
227
|
raise 'Text length too long. Use the "split_text() function to get a list of text segments'
|
|
262
228
|
|
|
263
|
-
# set value if none exist
|
|
264
|
-
meta = {} if meta is None else meta
|
|
265
|
-
|
|
266
|
-
if 'name' not in meta and name is None:
|
|
267
|
-
name = f'{self.vault}-{self.x}'
|
|
268
|
-
elif name is not None:
|
|
269
|
-
name = name
|
|
270
|
-
meta['name'] = name
|
|
271
|
-
meta['item_id'] = self.x # Store the item index in the metadata
|
|
272
|
-
|
|
273
|
-
if 'created_at' not in meta:
|
|
274
|
-
meta['created_at'] = datetime.datetime.utcnow().isoformat()
|
|
275
|
-
if 'updated_at' not in meta:
|
|
276
|
-
meta['updated_at'] = datetime.datetime.utcnow().isoformat()
|
|
277
|
-
|
|
278
229
|
# Add vector to vectorspace
|
|
279
230
|
self.vectors.add_item(self.x, vector)
|
|
280
|
-
|
|
281
|
-
# Add item and its metadata to the items list
|
|
282
|
-
item = {
|
|
283
|
-
"text": text,
|
|
284
|
-
"meta": meta
|
|
285
|
-
}
|
|
286
|
-
self.items.append(item)
|
|
231
|
+
self.items.append(itemize(self.vault, self.x, meta, text, name))
|
|
287
232
|
|
|
288
233
|
self.x += 1
|
|
289
234
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|