vector-vault 4.2.4__tar.gz → 4.2.6__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-4.2.4 → vector_vault-4.2.6}/PKG-INFO +1 -1
- {vector_vault-4.2.4 → vector_vault-4.2.6}/setup.py +1 -1
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vector_vault.egg-info/PKG-INFO +1 -1
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/cloudmanager.py +8 -17
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/itemize.py +25 -1
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/tools_gpt.py +1 -1
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/vault.py +146 -48
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/vecreq.py +28 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/LICENSE +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/README.md +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/setup.cfg +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vector_vault.egg-info/SOURCES.txt +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vector_vault.egg-info/dependency_links.txt +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vector_vault.egg-info/requires.txt +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vector_vault.egg-info/top_level.txt +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/__init__.py +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/ai.py +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/cloud_api.py +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/creds.py +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/download.py +0 -0
- {vector_vault-4.2.4 → vector_vault-4.2.6}/vectorvault/wrap.py +0 -0
|
@@ -17,13 +17,14 @@ from google.cloud import storage
|
|
|
17
17
|
from .creds import CustomCredentials
|
|
18
18
|
from .vecreq import call_proj, call_update
|
|
19
19
|
from .itemize import cloud_name
|
|
20
|
-
from .vault import ThreadPoolExecutor, as_completed,
|
|
20
|
+
from .vault import ThreadPoolExecutor, as_completed, time, json, os, tempfile, time
|
|
21
21
|
|
|
22
22
|
class CloudManager:
|
|
23
|
-
def __init__(self, user: str, api_key: str, vault: str):
|
|
23
|
+
def __init__(self, user: str, api_key: str, vault: str, ai_api: str = None):
|
|
24
24
|
self.user = user
|
|
25
25
|
self.api = api_key
|
|
26
26
|
self.vault = vault
|
|
27
|
+
self.ai_api = ai_api
|
|
27
28
|
# Create credentials
|
|
28
29
|
self.credentials = CustomCredentials(user, self.api)
|
|
29
30
|
# Instantiate the client
|
|
@@ -84,19 +85,10 @@ class CloudManager:
|
|
|
84
85
|
os.close(temp_file_descriptor)
|
|
85
86
|
return temp_file_path
|
|
86
87
|
|
|
87
|
-
def upload(self, item, text, meta):
|
|
88
|
-
self.upload_to_cloud(self.cloud_name(self.vault, item, self.user, self.api, item=True), text)
|
|
89
|
-
self.upload_to_cloud(self.cloud_name(self.vault, item, self.user, self.api, meta=True), json.dumps(meta))
|
|
90
|
-
|
|
91
|
-
def upload_personality_message(self, personality_message):
|
|
92
|
-
self.upload_to_cloud(f'{self.vault}/personality_message', personality_message)
|
|
93
|
-
|
|
94
|
-
def upload_custom_prompt(self, prompt):
|
|
95
|
-
self.upload_to_cloud(f'{self.vault}/prompt', prompt)
|
|
96
|
-
|
|
97
|
-
def upload_no_context_prompt(self, prompt):
|
|
98
|
-
self.upload_to_cloud(f'{self.vault}/no_context_prompt', prompt)
|
|
99
|
-
|
|
88
|
+
def upload(self, item, text, meta, vault = None):
|
|
89
|
+
self.upload_to_cloud(self.cloud_name(vault if vault else self.vault, item, self.user, self.api, item=True), text)
|
|
90
|
+
self.upload_to_cloud(self.cloud_name(vault if vault else self.vault, item, self.user, self.api, meta=True), json.dumps(meta))
|
|
91
|
+
|
|
100
92
|
def username(self, input_string):
|
|
101
93
|
return input_string.replace("@", "_at_").replace(".", "_dot_") + '_vvclient'
|
|
102
94
|
|
|
@@ -108,8 +100,7 @@ class CloudManager:
|
|
|
108
100
|
return _map
|
|
109
101
|
|
|
110
102
|
def update(self):
|
|
111
|
-
|
|
112
|
-
th.start()
|
|
103
|
+
call_update(self.user, self.vault, self.api)
|
|
113
104
|
|
|
114
105
|
def build_update(self):
|
|
115
106
|
_map = self.get_mapping()
|
|
@@ -91,4 +91,28 @@ def build_return(item_data, meta, distance=None):
|
|
|
91
91
|
"metadata": meta,
|
|
92
92
|
"distance": distance
|
|
93
93
|
}
|
|
94
|
-
return result
|
|
94
|
+
return result
|
|
95
|
+
|
|
96
|
+
def get_time_statement(now, message_time):
|
|
97
|
+
diff = now - message_time
|
|
98
|
+
days, seconds = diff.days, diff.seconds
|
|
99
|
+
human_readable_time = ""
|
|
100
|
+
|
|
101
|
+
if days >= 365:
|
|
102
|
+
years = days // 365
|
|
103
|
+
human_readable_time = f"{years} {'year' if years == 1 else 'years'} ago: "
|
|
104
|
+
elif days >= 30:
|
|
105
|
+
months = days // 30
|
|
106
|
+
human_readable_time = f"{months} {'month' if months == 1 else 'months'} ago: "
|
|
107
|
+
elif days >= 1:
|
|
108
|
+
human_readable_time = f"{days} {'day' if days == 1 else 'days'} ago: "
|
|
109
|
+
elif seconds >= 3600:
|
|
110
|
+
hours = seconds // 3600
|
|
111
|
+
human_readable_time = f"{hours} {'hour' if hours == 1 else 'hours'} ago: "
|
|
112
|
+
elif seconds >= 60:
|
|
113
|
+
minutes = seconds // 60
|
|
114
|
+
human_readable_time = f"{minutes} {'minute' if minutes == 1 else 'minutes'} ago: "
|
|
115
|
+
else:
|
|
116
|
+
human_readable_time = "just now: "
|
|
117
|
+
|
|
118
|
+
return human_readable_time
|
|
@@ -23,19 +23,19 @@ import re
|
|
|
23
23
|
import json
|
|
24
24
|
import traceback
|
|
25
25
|
import random
|
|
26
|
-
from datetime import datetime
|
|
27
26
|
from typing import List
|
|
28
|
-
from
|
|
27
|
+
from ai import AI, openai
|
|
29
28
|
from threading import Thread as T
|
|
29
|
+
from datetime import datetime, timedelta
|
|
30
|
+
from .concurrent.futures import ThreadPoolExecutor, as_completed
|
|
30
31
|
from .cloudmanager import CloudManager
|
|
31
|
-
from .
|
|
32
|
-
from .
|
|
33
|
-
from .vecreq import call_get_similar
|
|
32
|
+
from .itemize import itemize, name_vecs, get_item, get_vectors, build_return, cloud_name, name_map, get_time_statement
|
|
33
|
+
from .vecreq import call_get_similar, call_cloud_save
|
|
34
34
|
from .tools_gpt import ToolsGPT
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
class Vault:
|
|
38
|
-
def __init__(self, user: str = None, api_key: str = None,
|
|
38
|
+
def __init__(self, user: str = None, api_key: str = None, openai_key: str = None, vault: str = None, embeddings_model: str = None, verbose: bool = False, conversation_user_id: str = None):
|
|
39
39
|
'''
|
|
40
40
|
### Create a vector database instance like this:
|
|
41
41
|
```
|
|
@@ -75,11 +75,11 @@ class Vault:
|
|
|
75
75
|
self.user = user.lower()
|
|
76
76
|
self.vault = vault.strip() if vault else 'home'
|
|
77
77
|
self.api = api_key
|
|
78
|
-
t = T(target=self.connect_to_cloud)
|
|
79
|
-
t.start()
|
|
80
78
|
if openai_key:
|
|
81
79
|
self.openai_key = openai_key
|
|
82
80
|
openai.api_key = self.openai_key
|
|
81
|
+
t = T(target=self.connect_to_cloud)
|
|
82
|
+
t.start()
|
|
83
83
|
self.embeddings_model = embeddings_model if embeddings_model else 'text-embedding-3-small'
|
|
84
84
|
self.dims = 1536 if embeddings_model != 'text-embedding-3-large' else 3072
|
|
85
85
|
self.vectors = get_vectors(self.dims)
|
|
@@ -94,12 +94,13 @@ class Vault:
|
|
|
94
94
|
self.ai_loaded = False
|
|
95
95
|
self.tools = ToolsGPT(verbose=verbose)
|
|
96
96
|
self.rate_limiter = RateLimiter(max_attempts=30)
|
|
97
|
+
self.cuid = conversation_user_id
|
|
97
98
|
t.join()
|
|
98
99
|
|
|
99
100
|
|
|
100
101
|
def connect_to_cloud(self):
|
|
101
102
|
try:
|
|
102
|
-
self.cloud_manager = CloudManager(self.user, self.api, self.vault)
|
|
103
|
+
self.cloud_manager = CloudManager(self.user, self.api, self.vault, self.openai_key)
|
|
103
104
|
print(f'Connected vault: {self.vault}') if self.verbose else 0
|
|
104
105
|
|
|
105
106
|
except Exception as e:
|
|
@@ -113,6 +114,8 @@ class Vault:
|
|
|
113
114
|
Returns a list of vaults within the current vault directory
|
|
114
115
|
'''
|
|
115
116
|
vault = self.vault if vault is None else vault
|
|
117
|
+
if self.cloud_manager is None:
|
|
118
|
+
time.sleep(.3)
|
|
116
119
|
return self.cloud_manager.list_vaults(vault)
|
|
117
120
|
|
|
118
121
|
|
|
@@ -218,7 +221,7 @@ class Vault:
|
|
|
218
221
|
return prompt
|
|
219
222
|
|
|
220
223
|
|
|
221
|
-
def save(self, trees: int = 10):
|
|
224
|
+
def save(self, trees: int = 10, vault = None):
|
|
222
225
|
'''
|
|
223
226
|
Saves all the data added locally to the Cloud. All Vault references are Cloud references.
|
|
224
227
|
To add data to your Vault and access it later, you must first call add(), then get_vectors(), and finally save().
|
|
@@ -235,10 +238,10 @@ class Vault:
|
|
|
235
238
|
with ThreadPoolExecutor() as executor:
|
|
236
239
|
for item in self.items:
|
|
237
240
|
item_text, item_id, item_meta = get_item(item)
|
|
238
|
-
executor.submit(self.cloud_manager.upload, self.map.get(str(item_id)), item_text, item_meta)
|
|
241
|
+
executor.submit(self.cloud_manager.upload, self.map.get(str(item_id)), item_text, item_meta, vault = vault if vault else self.vault)
|
|
239
242
|
total_saved_items += 1
|
|
240
243
|
|
|
241
|
-
self.upload_vectors()
|
|
244
|
+
self.upload_vectors(vault if vault else self.vault)
|
|
242
245
|
print(f"upload time --- {(time.time() - start_time)} seconds --- {total_saved_items} items saved") if self.verbose else 0
|
|
243
246
|
|
|
244
247
|
|
|
@@ -389,6 +392,8 @@ class Vault:
|
|
|
389
392
|
def check_index(self):
|
|
390
393
|
if not self.x_checked:
|
|
391
394
|
start_time = time.time()
|
|
395
|
+
while self.cloud_manager is None:
|
|
396
|
+
time.sleep(.01)
|
|
392
397
|
if self.cloud_manager.vault_exists(name_vecs(self.vault, self.user, self.api)):
|
|
393
398
|
if not self.vecs_loaded:
|
|
394
399
|
self.load_vectors()
|
|
@@ -398,15 +403,16 @@ class Vault:
|
|
|
398
403
|
print("initialize index --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
|
|
399
404
|
|
|
400
405
|
|
|
401
|
-
def load_mapping(self):
|
|
406
|
+
def load_mapping(self, vault = None):
|
|
402
407
|
'''Internal function only'''
|
|
408
|
+
vault = vault if vault else self.vault
|
|
403
409
|
try: # try to get the map
|
|
404
|
-
temp_file_path = self.cloud_manager.download_to_temp_file(name_map(
|
|
410
|
+
temp_file_path = self.cloud_manager.download_to_temp_file(name_map(vault, self.user, self.api))
|
|
405
411
|
with open(temp_file_path, 'r') as json_file:
|
|
406
412
|
self.map = json.load(json_file)
|
|
407
413
|
os.remove(temp_file_path)
|
|
408
414
|
except: # it doesn't exist
|
|
409
|
-
if self.cloud_manager.vault_exists(name_vecs(
|
|
415
|
+
if self.cloud_manager.vault_exists(name_vecs(vault, self.user, self.api)): # but if the vault does
|
|
410
416
|
self.map = {str(i): str(i) for i in range(self.vectors.get_n_items())}
|
|
411
417
|
|
|
412
418
|
def add_to_map(self):
|
|
@@ -414,11 +420,12 @@ class Vault:
|
|
|
414
420
|
self.x +=1
|
|
415
421
|
|
|
416
422
|
|
|
417
|
-
def load_vectors(self):
|
|
423
|
+
def load_vectors(self, vault = None):
|
|
418
424
|
start_time = time.time()
|
|
425
|
+
vault = vault if vault else self.vault
|
|
419
426
|
t = T(target=self.load_mapping())
|
|
420
427
|
t.start()
|
|
421
|
-
temp_file_path = self.cloud_manager.download_to_temp_file(name_vecs(
|
|
428
|
+
temp_file_path = self.cloud_manager.download_to_temp_file(name_vecs(vault, self.user, self.api))
|
|
422
429
|
self.vectors.load(temp_file_path)
|
|
423
430
|
os.remove(temp_file_path)
|
|
424
431
|
t.join()
|
|
@@ -535,19 +542,20 @@ class Vault:
|
|
|
535
542
|
self.vectors = new_index
|
|
536
543
|
|
|
537
544
|
|
|
538
|
-
def upload_vectors(self):
|
|
545
|
+
def upload_vectors(self, vault = None):
|
|
546
|
+
vault = vault if vault else self.vault
|
|
539
547
|
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
|
540
548
|
vector_temp_file_path = temp_file.name
|
|
541
549
|
self.vectors.save(vector_temp_file_path)
|
|
542
550
|
byte = os.path.getsize(vector_temp_file_path)
|
|
543
|
-
self.cloud_manager.upload_temp_file(vector_temp_file_path, name_vecs(
|
|
551
|
+
self.cloud_manager.upload_temp_file(vector_temp_file_path, name_vecs(vault, self.user, self.api, byte))
|
|
544
552
|
|
|
545
553
|
map_temp_file_path = None
|
|
546
554
|
with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_file:
|
|
547
555
|
map_temp_file_path = temp_file.name
|
|
548
556
|
json.dump(self.map, temp_file, indent=2)
|
|
549
557
|
|
|
550
|
-
self.cloud_manager.upload_temp_file(map_temp_file_path, name_map(
|
|
558
|
+
self.cloud_manager.upload_temp_file(map_temp_file_path, name_map(vault, self.user, self.api, byte))
|
|
551
559
|
if os.path.exists(map_temp_file_path):
|
|
552
560
|
os.remove(map_temp_file_path)
|
|
553
561
|
|
|
@@ -662,12 +670,13 @@ class Vault:
|
|
|
662
670
|
return results
|
|
663
671
|
|
|
664
672
|
|
|
665
|
-
def get_items_by_vector(self, vector: list, n: int = 4, include_distances: bool = False):
|
|
673
|
+
def get_items_by_vector(self, vector: list, n: int = 4, include_distances: bool = False, vault = None) -> list:
|
|
666
674
|
'''
|
|
667
675
|
Internal function that returns vector similar items. Requires input vector, returns similar items
|
|
668
676
|
'''
|
|
669
677
|
try:
|
|
670
|
-
self.
|
|
678
|
+
vault = vault if vault else self.vault
|
|
679
|
+
self.load_vectors(vault)
|
|
671
680
|
start_time = time.time()
|
|
672
681
|
if not include_distances:
|
|
673
682
|
vecs = self.vectors.get_nns_by_vector(vector, n)
|
|
@@ -675,8 +684,8 @@ class Vault:
|
|
|
675
684
|
|
|
676
685
|
def fetch_item(index, vec):
|
|
677
686
|
# Function to fetch a single item, to be run in parallel
|
|
678
|
-
item_data = self.cloud_manager.download_text_from_cloud(cloud_name(
|
|
679
|
-
meta_data = self.cloud_manager.download_text_from_cloud(cloud_name(
|
|
687
|
+
item_data = self.cloud_manager.download_text_from_cloud(cloud_name(vault, self.map[str(vec)], self.user, self.api, item=True))
|
|
688
|
+
meta_data = self.cloud_manager.download_text_from_cloud(cloud_name(vault, self.map[str(vec)], self.user, self.api, meta=True))
|
|
680
689
|
meta = json.loads(meta_data)
|
|
681
690
|
return index, build_return(item_data, meta)
|
|
682
691
|
|
|
@@ -695,8 +704,8 @@ class Vault:
|
|
|
695
704
|
|
|
696
705
|
def fetch_item(index, vec, distance):
|
|
697
706
|
# Function to fetch a single item, to be run in parallel
|
|
698
|
-
item_data = self.cloud_manager.download_text_from_cloud(cloud_name(
|
|
699
|
-
meta_data = self.cloud_manager.download_text_from_cloud(cloud_name(
|
|
707
|
+
item_data = self.cloud_manager.download_text_from_cloud(cloud_name(vault, self.map[str(vec)], self.user, self.api, item=True))
|
|
708
|
+
meta_data = self.cloud_manager.download_text_from_cloud(cloud_name(vault, self.map[str(vec)], self.user, self.api, meta=True))
|
|
700
709
|
meta = json.loads(meta_data)
|
|
701
710
|
return index, build_return(item_data, meta, distance)
|
|
702
711
|
|
|
@@ -713,17 +722,17 @@ class Vault:
|
|
|
713
722
|
return [{'data': 'No data has been added', 'metadata': {'no meta': 'No metadata has been added'}}]
|
|
714
723
|
|
|
715
724
|
|
|
716
|
-
def get_similar_local(self, text: str, n: int = 4, include_distances: bool = False):
|
|
725
|
+
def get_similar_local(self, text: str, n: int = 4, include_distances: bool = False, vault = None):
|
|
717
726
|
'''
|
|
718
727
|
Returns similar items from the Vault as the one you entered, but locally
|
|
719
728
|
(saves a few milliseconds and is sometimes used on production builds)
|
|
720
729
|
'''
|
|
721
730
|
self.cloud_manager.update()
|
|
722
731
|
vector = self.process_batch([text], never_stop=False, loop_timeout=180)[0]
|
|
723
|
-
return self.get_items_by_vector(vector, n, include_distances=include_distances)
|
|
732
|
+
return self.get_items_by_vector(vector, n, include_distances = include_distances, vault = vault if vault else self.vault)
|
|
724
733
|
|
|
725
734
|
|
|
726
|
-
def get_similar(self, text: str, n: int = 4, include_distances: bool = False):
|
|
735
|
+
def get_similar(self, text: str, n: int = 4, include_distances: bool = False, vault = None):
|
|
727
736
|
'''
|
|
728
737
|
Returns similar items from the Vault as the text you enter.
|
|
729
738
|
|
|
@@ -731,21 +740,21 @@ class Vault:
|
|
|
731
740
|
The distance can be useful for assessing similarity differences in the items returned.
|
|
732
741
|
Each item has its' own distance number, and this changes the structure of the output.
|
|
733
742
|
'''
|
|
734
|
-
return call_get_similar(self.user, self.vault, self.api, self.openai_key, text, n, include_distances=include_distances, verbose=self.verbose)
|
|
743
|
+
return call_get_similar(self.user, vault if vault else self.vault, self.api, self.openai_key, text, n, include_distances=include_distances, verbose=self.verbose)
|
|
735
744
|
|
|
736
745
|
|
|
737
|
-
def add_item(self, text: str, meta: dict = None, name: str = None):
|
|
746
|
+
def add_item(self, text: str, meta: dict = None, name: str = None, vault = None):
|
|
738
747
|
"""
|
|
739
748
|
If your text length is greater than 15000 characters, you should use Vault.split_text(your_text) to
|
|
740
749
|
get a list of text segments that are the right size
|
|
741
750
|
"""
|
|
742
751
|
self.check_index()
|
|
743
|
-
new_item = itemize(self.vault, self.x, meta, text, name)
|
|
752
|
+
new_item = itemize(vault if vault else self.vault, self.x, meta, text, name)
|
|
744
753
|
self.items.append(new_item)
|
|
745
754
|
self.add_to_map()
|
|
746
755
|
|
|
747
756
|
|
|
748
|
-
def add(self, text: str, meta: dict = None, name: str = None, split: bool = False, split_size: int = 1000, max_threshold: int = 16000):
|
|
757
|
+
def add(self, text: str, meta: dict = None, name: str = None, split: bool = False, split_size: int = 1000, max_threshold: int = 16000, vault = None):
|
|
749
758
|
"""
|
|
750
759
|
If your text length is greater than 4000 tokens, Vault.split_text(your_text)
|
|
751
760
|
will automatically be added
|
|
@@ -759,18 +768,19 @@ class Vault:
|
|
|
759
768
|
else:
|
|
760
769
|
texts = [text]
|
|
761
770
|
for text in texts:
|
|
762
|
-
self.add_item(text, meta, name)
|
|
771
|
+
self.add_item(text, meta, name, vault if vault else self.vault)
|
|
763
772
|
|
|
764
773
|
|
|
765
|
-
def add_n_save(self, text: str, meta: dict = None, name: str = None, split: bool = False, split_size: int = 1000, max_threshold: int = 16000):
|
|
774
|
+
def add_n_save(self, text: str, meta: dict = None, name: str = None, split: bool = False, split_size: int = 1000, max_threshold: int = 16000, vault = None):
|
|
766
775
|
"""
|
|
767
776
|
Adds data, gets vectors, then saves the data to the cloud in one call
|
|
768
777
|
If your text length is greater than 4000 tokens, your text will automatically be split by
|
|
769
778
|
Vault.split_text(your_text).
|
|
770
779
|
"""
|
|
771
|
-
self.add(text=text, meta=meta, name=name, split=split, split_size=split_size, max_threshold=max_threshold)
|
|
780
|
+
self.add(text=text, meta=meta, name=name, split=split, split_size=split_size, max_threshold=max_threshold, vault=vault if vault else self.vault)
|
|
772
781
|
self.get_vectors()
|
|
773
|
-
self.save()
|
|
782
|
+
self.save(vault = vault if vault else self.vault)
|
|
783
|
+
T(target=self.clear_cache).start()
|
|
774
784
|
|
|
775
785
|
|
|
776
786
|
def add_item_with_vector(self, text: str, vector: list, meta: dict = None, name: str = None):
|
|
@@ -851,7 +861,7 @@ class Vault:
|
|
|
851
861
|
print("get vectors time --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
|
|
852
862
|
|
|
853
863
|
|
|
854
|
-
def get_chat(self, text: str = None, history: str =
|
|
864
|
+
def get_chat(self, text: str = None, history: str = '', summary: bool = False, get_context: bool = False,
|
|
855
865
|
n_context: int = 4, return_context: bool = False, history_search: bool = False, smart_history_search: bool = False,
|
|
856
866
|
model: str = 'gpt-3.5-turbo', include_context_meta: bool = False, custom_prompt: bool = False,
|
|
857
867
|
local: bool =False, temperature: int = 0, timeout: int = 300):
|
|
@@ -936,10 +946,11 @@ class Vault:
|
|
|
936
946
|
self.load_ai()
|
|
937
947
|
model = model.lower()
|
|
938
948
|
start_time = time.time()
|
|
939
|
-
|
|
940
|
-
if
|
|
941
|
-
|
|
942
|
-
|
|
949
|
+
|
|
950
|
+
history_time = time.time() if self.cuid else None
|
|
951
|
+
history = self.get_conversation_history(self.cuid, text) if self.cuid else history
|
|
952
|
+
print('history retrieval took:', history_time - time.time()) if self.cuid and self.verbose else None
|
|
953
|
+
|
|
943
954
|
if text:
|
|
944
955
|
inputs = [text]
|
|
945
956
|
else:
|
|
@@ -1004,12 +1015,13 @@ class Vault:
|
|
|
1004
1015
|
print(f"API Failed too many times, exiting loop: {e}.")
|
|
1005
1016
|
break
|
|
1006
1017
|
|
|
1018
|
+
self.update_conversation_history(self.cuid, response) if self.cuid else None
|
|
1007
1019
|
print("get chat time --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
|
|
1008
1020
|
|
|
1009
1021
|
return {'response': response, 'context': context} if return_context else response
|
|
1010
1022
|
|
|
1011
1023
|
|
|
1012
|
-
def get_chat_stream(self, text: str = None, history: str =
|
|
1024
|
+
def get_chat_stream(self, text: str = None, history: str = '', summary: bool = False, get_context: bool = False,
|
|
1013
1025
|
n_context: int = 4, return_context: bool = False, history_search: bool = False, smart_history_search: bool = False,
|
|
1014
1026
|
model: str ='gpt-3.5-turbo', include_context_meta: bool = False, metatag: bool = False,
|
|
1015
1027
|
metatag_prefixes: bool = False, metatag_suffixes: bool = False, custom_prompt: bool = False,
|
|
@@ -1082,9 +1094,10 @@ class Vault:
|
|
|
1082
1094
|
self.load_ai()
|
|
1083
1095
|
model = model.lower()
|
|
1084
1096
|
start_time = time.time()
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1097
|
+
|
|
1098
|
+
history_time = time.time()
|
|
1099
|
+
history = self.get_conversation_history(self.cuid, text) if self.cuid else history
|
|
1100
|
+
print('history retrieval took:', history_time - time.time()) if self.cuid and self.verbose else None
|
|
1088
1101
|
|
|
1089
1102
|
if text:
|
|
1090
1103
|
inputs = [text]
|
|
@@ -1098,7 +1111,7 @@ class Vault:
|
|
|
1098
1111
|
for segment in inputs:
|
|
1099
1112
|
start_time = time.time()
|
|
1100
1113
|
exceptions = 0
|
|
1101
|
-
|
|
1114
|
+
full_response = ''
|
|
1102
1115
|
while True:
|
|
1103
1116
|
try:
|
|
1104
1117
|
if summary and not get_context:
|
|
@@ -1114,6 +1127,7 @@ class Vault:
|
|
|
1114
1127
|
current_chunk = segment[start_index:end_index]
|
|
1115
1128
|
# Process the current chunk and concatenate the response
|
|
1116
1129
|
for word in self.ai.summarize_stream(current_chunk, model=model, custom_prompt=custom_prompt, temperature=temperature):
|
|
1130
|
+
full_response += word
|
|
1117
1131
|
yield word
|
|
1118
1132
|
yield ' '
|
|
1119
1133
|
|
|
@@ -1121,6 +1135,7 @@ class Vault:
|
|
|
1121
1135
|
except Exception as e:
|
|
1122
1136
|
raise e
|
|
1123
1137
|
if counter == len(inputs):
|
|
1138
|
+
self.update_conversation_history(self.cuid, full_response) if self.cuid else None
|
|
1124
1139
|
yield '!END'
|
|
1125
1140
|
self.rate_limiter.on_success()
|
|
1126
1141
|
|
|
@@ -1138,6 +1153,7 @@ class Vault:
|
|
|
1138
1153
|
|
|
1139
1154
|
try:
|
|
1140
1155
|
for word in self.ai.llm_w_context_stream(segment, input_, history, model=model, custom_prompt=custom_prompt, temperature=temperature):
|
|
1156
|
+
full_response += word
|
|
1141
1157
|
yield word
|
|
1142
1158
|
self.rate_limiter.on_success()
|
|
1143
1159
|
except Exception as e:
|
|
@@ -1157,20 +1173,25 @@ class Vault:
|
|
|
1157
1173
|
for i in range(len(metatag)):
|
|
1158
1174
|
yield str(metatag_prefixes[i]) + str(item['metadata'][f'{metatag[i]}'])
|
|
1159
1175
|
yield item['data']
|
|
1176
|
+
self.update_conversation_history(self.cuid, full_response) if self.cuid else None
|
|
1160
1177
|
yield '!END'
|
|
1161
1178
|
self.rate_limiter.on_success()
|
|
1162
1179
|
else:
|
|
1180
|
+
self.update_conversation_history(self.cuid, full_response) if self.cuid else None
|
|
1163
1181
|
yield '!END'
|
|
1164
1182
|
self.rate_limiter.on_success()
|
|
1165
1183
|
|
|
1166
1184
|
else:
|
|
1167
1185
|
try:
|
|
1168
1186
|
for word in self.ai.llm_stream(segment, history, model=model, custom_prompt=custom_prompt, temperature=temperature):
|
|
1187
|
+
full_response += word
|
|
1169
1188
|
yield word
|
|
1170
1189
|
self.rate_limiter.on_success()
|
|
1171
1190
|
except Exception as e:
|
|
1172
1191
|
raise e
|
|
1192
|
+
self.update_conversation_history(self.cuid, full_response) if self.cuid else None
|
|
1173
1193
|
yield '!END'
|
|
1194
|
+
|
|
1174
1195
|
self.rate_limiter.on_success()
|
|
1175
1196
|
break
|
|
1176
1197
|
except Exception as e:
|
|
@@ -1250,6 +1271,83 @@ class Vault:
|
|
|
1250
1271
|
yield f"data: {json.dumps({'data': word})} \n\n"
|
|
1251
1272
|
|
|
1252
1273
|
|
|
1274
|
+
def update_conversation_history(self, conversation_id, message, metadata_list = None, user = True):
|
|
1275
|
+
message = f'User: {message}' if user else f'AI: {message}'
|
|
1276
|
+
try:
|
|
1277
|
+
metadata_list = metadata_list if metadata_list else json.loads(self.cloud_manager.download_text_from_cloud(f'user_history/{conversation_id}/metadata'))
|
|
1278
|
+
except:
|
|
1279
|
+
metadata_list = []
|
|
1280
|
+
message_id = f"{time.time():.0f}" # Current time
|
|
1281
|
+
metadata_list.append({ 'M': message_id, 'L': len(message) })
|
|
1282
|
+
t1 = T(target=self.cloud_manager.upload_to_cloud, args=(f'user_history/{conversation_id}/{message_id}', message))
|
|
1283
|
+
t2 = T(target=self.cloud_manager.upload_to_cloud, args=(f'user_history/{conversation_id}/metadata', json.dumps(metadata_list)))
|
|
1284
|
+
t1.start()
|
|
1285
|
+
t2.start()
|
|
1286
|
+
call_cloud_save(self.user, self.api, self.openai_key, f'user_history/{conversation_id}/vectors', self.embeddings_model, message, name=message_id, split_size=3000)
|
|
1287
|
+
t1.join()
|
|
1288
|
+
t2.join()
|
|
1289
|
+
|
|
1290
|
+
def get_conversation_history(self, conversation_id, message):
|
|
1291
|
+
def download_conversation_metadata():
|
|
1292
|
+
try:
|
|
1293
|
+
return json.loads(self.cloud_manager.download_text_from_cloud(f'user_history/{conversation_id}/metadata'))
|
|
1294
|
+
except:
|
|
1295
|
+
return []
|
|
1296
|
+
|
|
1297
|
+
def download_conversation_message(msg_id):
|
|
1298
|
+
try:
|
|
1299
|
+
return self.cloud_manager.download_text_from_cloud(f'user_history/{conversation_id}/{msg_id}')
|
|
1300
|
+
except:
|
|
1301
|
+
return []
|
|
1302
|
+
|
|
1303
|
+
def golden_retriever(metadata_list):
|
|
1304
|
+
one_hour_ago = datetime.now() - timedelta(hours=1)
|
|
1305
|
+
return [metadata['M'] for metadata in reversed(metadata_list) if datetime.fromtimestamp(float(metadata['M'])) >= one_hour_ago]
|
|
1306
|
+
|
|
1307
|
+
def vector_search_conversation_history(message):
|
|
1308
|
+
return self.get_similar_local(message, vault=f'user_history/{conversation_id}/vectors')
|
|
1309
|
+
|
|
1310
|
+
history = ''
|
|
1311
|
+
|
|
1312
|
+
try:
|
|
1313
|
+
meta = download_conversation_metadata()
|
|
1314
|
+
except:
|
|
1315
|
+
meta = None
|
|
1316
|
+
|
|
1317
|
+
message_ids = golden_retriever(meta) if meta != None else []
|
|
1318
|
+
|
|
1319
|
+
update = T(target=self.update_conversation_history, args=(conversation_id, message, meta if meta else None))
|
|
1320
|
+
update.start()
|
|
1321
|
+
|
|
1322
|
+
print('message_ids:', message_ids) if self.verbose else None
|
|
1323
|
+
|
|
1324
|
+
if message_ids != []:
|
|
1325
|
+
history_lines = []
|
|
1326
|
+
with ThreadPoolExecutor(max_workers=10) as executor:
|
|
1327
|
+
future_to_message_id = {executor.submit(download_conversation_message, message_id): message_id for message_id in message_ids}
|
|
1328
|
+
|
|
1329
|
+
# Iterate over the futures as they complete (preserves order)
|
|
1330
|
+
for future in as_completed(future_to_message_id):
|
|
1331
|
+
message_content = future.result()
|
|
1332
|
+
history_lines.append(message_content)
|
|
1333
|
+
|
|
1334
|
+
history = '\n'.join(history_lines)
|
|
1335
|
+
history = "Recent conversation history:" + history
|
|
1336
|
+
|
|
1337
|
+
vector_similar_results = vector_search_conversation_history(message)
|
|
1338
|
+
vector_history = []
|
|
1339
|
+
now = datetime.now()
|
|
1340
|
+
for i in vector_similar_results:
|
|
1341
|
+
message_time = datetime.fromtimestamp(float(i['name']))
|
|
1342
|
+
data = i['data']
|
|
1343
|
+
vector_history.append(f'{get_time_statement(now, message_time)} {data}')
|
|
1344
|
+
|
|
1345
|
+
history = history + "Vector search conversation history:" + '\n'.join(vector_history)
|
|
1346
|
+
|
|
1347
|
+
update.join()
|
|
1348
|
+
return history
|
|
1349
|
+
|
|
1350
|
+
|
|
1253
1351
|
class RateLimiter:
|
|
1254
1352
|
def __init__(self, max_attempts=30):
|
|
1255
1353
|
self.base_delay = 1 # Base delay of 1 second
|
|
@@ -1265,4 +1363,4 @@ class RateLimiter:
|
|
|
1265
1363
|
def on_failure(self):
|
|
1266
1364
|
# Apply exponential backoff with a random jitter
|
|
1267
1365
|
self.current_delay = min(self.max_delay, random.uniform(self.base_delay, self.current_delay * self.backoff_factor))
|
|
1268
|
-
time.sleep(self.current_delay)
|
|
1366
|
+
time.sleep(self.current_delay)
|
|
@@ -113,6 +113,34 @@ def call_update(email, vault, api):
|
|
|
113
113
|
else:
|
|
114
114
|
raise Exception(f"Request failed with status {response.status_code}")
|
|
115
115
|
|
|
116
|
+
def call_cloud_save(user, api_key, openai_key, vault, embeddings_model, text, meta = None, name = None, split = None, split_size = None):
|
|
117
|
+
url = "https://api.vectorvault.io/add_cloud"
|
|
118
|
+
|
|
119
|
+
# Define the data payload
|
|
120
|
+
data = {
|
|
121
|
+
'user': user,
|
|
122
|
+
'vault': vault,
|
|
123
|
+
'api_key': api_key,
|
|
124
|
+
'openai_key': openai_key,
|
|
125
|
+
"text": text,
|
|
126
|
+
"embeddings_model": embeddings_model,
|
|
127
|
+
"meta": meta,
|
|
128
|
+
"name": name,
|
|
129
|
+
"split": split,
|
|
130
|
+
"split_size": split_size,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Make the POST request
|
|
134
|
+
response = requests.post(url, json=data)
|
|
135
|
+
|
|
136
|
+
# Check the request was successful
|
|
137
|
+
if response.status_code == 200:
|
|
138
|
+
# Parse the response JSON
|
|
139
|
+
data = response.json()
|
|
140
|
+
return data
|
|
141
|
+
else:
|
|
142
|
+
raise Exception(f"Request failed with status {response.status_code}")
|
|
143
|
+
|
|
116
144
|
|
|
117
145
|
def call_get_chat(user, vault, api_key, openai_key, text, history=None, summary=False, get_context=False, n_context=4, return_context=False, expansion=False, history_search=False, model='gpt-3.5-turbo', include_context_meta=False):
|
|
118
146
|
url = "https://api.vectorvault.io/get_chat"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|