vector-vault 4.2.5__tar.gz → 4.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-4.2.5 → vector_vault-4.2.7}/PKG-INFO +1 -1
- {vector_vault-4.2.5 → vector_vault-4.2.7}/setup.py +1 -1
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/PKG-INFO +1 -1
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/cloudmanager.py +8 -17
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/itemize.py +25 -1
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/tools_gpt.py +1 -1
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/vault.py +144 -48
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/vecreq.py +28 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/LICENSE +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/README.md +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/setup.cfg +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/SOURCES.txt +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/dependency_links.txt +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/requires.txt +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/top_level.txt +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/__init__.py +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/ai.py +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/cloud_api.py +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/creds.py +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/download.py +0 -0
- {vector_vault-4.2.5 → vector_vault-4.2.7}/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 concurrent.futures import ThreadPoolExecutor, as_completed
|
|
29
27
|
from threading import Thread as T
|
|
30
|
-
from
|
|
28
|
+
from datetime import datetime, timedelta
|
|
29
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
31
30
|
from .ai import AI, openai
|
|
32
|
-
from .
|
|
33
|
-
from .
|
|
31
|
+
from .cloudmanager import CloudManager
|
|
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:
|
|
@@ -220,7 +221,7 @@ class Vault:
|
|
|
220
221
|
return prompt
|
|
221
222
|
|
|
222
223
|
|
|
223
|
-
def save(self, trees: int = 10):
|
|
224
|
+
def save(self, trees: int = 10, vault = None):
|
|
224
225
|
'''
|
|
225
226
|
Saves all the data added locally to the Cloud. All Vault references are Cloud references.
|
|
226
227
|
To add data to your Vault and access it later, you must first call add(), then get_vectors(), and finally save().
|
|
@@ -237,10 +238,10 @@ class Vault:
|
|
|
237
238
|
with ThreadPoolExecutor() as executor:
|
|
238
239
|
for item in self.items:
|
|
239
240
|
item_text, item_id, item_meta = get_item(item)
|
|
240
|
-
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)
|
|
241
242
|
total_saved_items += 1
|
|
242
243
|
|
|
243
|
-
self.upload_vectors()
|
|
244
|
+
self.upload_vectors(vault if vault else self.vault)
|
|
244
245
|
print(f"upload time --- {(time.time() - start_time)} seconds --- {total_saved_items} items saved") if self.verbose else 0
|
|
245
246
|
|
|
246
247
|
|
|
@@ -391,6 +392,8 @@ class Vault:
|
|
|
391
392
|
def check_index(self):
|
|
392
393
|
if not self.x_checked:
|
|
393
394
|
start_time = time.time()
|
|
395
|
+
while self.cloud_manager is None:
|
|
396
|
+
time.sleep(.01)
|
|
394
397
|
if self.cloud_manager.vault_exists(name_vecs(self.vault, self.user, self.api)):
|
|
395
398
|
if not self.vecs_loaded:
|
|
396
399
|
self.load_vectors()
|
|
@@ -400,15 +403,16 @@ class Vault:
|
|
|
400
403
|
print("initialize index --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
|
|
401
404
|
|
|
402
405
|
|
|
403
|
-
def load_mapping(self):
|
|
406
|
+
def load_mapping(self, vault = None):
|
|
404
407
|
'''Internal function only'''
|
|
408
|
+
vault = vault if vault else self.vault
|
|
405
409
|
try: # try to get the map
|
|
406
|
-
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))
|
|
407
411
|
with open(temp_file_path, 'r') as json_file:
|
|
408
412
|
self.map = json.load(json_file)
|
|
409
413
|
os.remove(temp_file_path)
|
|
410
414
|
except: # it doesn't exist
|
|
411
|
-
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
|
|
412
416
|
self.map = {str(i): str(i) for i in range(self.vectors.get_n_items())}
|
|
413
417
|
|
|
414
418
|
def add_to_map(self):
|
|
@@ -416,11 +420,12 @@ class Vault:
|
|
|
416
420
|
self.x +=1
|
|
417
421
|
|
|
418
422
|
|
|
419
|
-
def load_vectors(self):
|
|
423
|
+
def load_vectors(self, vault = None):
|
|
420
424
|
start_time = time.time()
|
|
425
|
+
vault = vault if vault else self.vault
|
|
421
426
|
t = T(target=self.load_mapping())
|
|
422
427
|
t.start()
|
|
423
|
-
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))
|
|
424
429
|
self.vectors.load(temp_file_path)
|
|
425
430
|
os.remove(temp_file_path)
|
|
426
431
|
t.join()
|
|
@@ -537,19 +542,20 @@ class Vault:
|
|
|
537
542
|
self.vectors = new_index
|
|
538
543
|
|
|
539
544
|
|
|
540
|
-
def upload_vectors(self):
|
|
545
|
+
def upload_vectors(self, vault = None):
|
|
546
|
+
vault = vault if vault else self.vault
|
|
541
547
|
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
|
542
548
|
vector_temp_file_path = temp_file.name
|
|
543
549
|
self.vectors.save(vector_temp_file_path)
|
|
544
550
|
byte = os.path.getsize(vector_temp_file_path)
|
|
545
|
-
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))
|
|
546
552
|
|
|
547
553
|
map_temp_file_path = None
|
|
548
554
|
with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_file:
|
|
549
555
|
map_temp_file_path = temp_file.name
|
|
550
556
|
json.dump(self.map, temp_file, indent=2)
|
|
551
557
|
|
|
552
|
-
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))
|
|
553
559
|
if os.path.exists(map_temp_file_path):
|
|
554
560
|
os.remove(map_temp_file_path)
|
|
555
561
|
|
|
@@ -664,12 +670,13 @@ class Vault:
|
|
|
664
670
|
return results
|
|
665
671
|
|
|
666
672
|
|
|
667
|
-
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:
|
|
668
674
|
'''
|
|
669
675
|
Internal function that returns vector similar items. Requires input vector, returns similar items
|
|
670
676
|
'''
|
|
671
677
|
try:
|
|
672
|
-
self.
|
|
678
|
+
vault = vault if vault else self.vault
|
|
679
|
+
self.load_vectors(vault)
|
|
673
680
|
start_time = time.time()
|
|
674
681
|
if not include_distances:
|
|
675
682
|
vecs = self.vectors.get_nns_by_vector(vector, n)
|
|
@@ -677,8 +684,8 @@ class Vault:
|
|
|
677
684
|
|
|
678
685
|
def fetch_item(index, vec):
|
|
679
686
|
# Function to fetch a single item, to be run in parallel
|
|
680
|
-
item_data = self.cloud_manager.download_text_from_cloud(cloud_name(
|
|
681
|
-
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))
|
|
682
689
|
meta = json.loads(meta_data)
|
|
683
690
|
return index, build_return(item_data, meta)
|
|
684
691
|
|
|
@@ -697,8 +704,8 @@ class Vault:
|
|
|
697
704
|
|
|
698
705
|
def fetch_item(index, vec, distance):
|
|
699
706
|
# Function to fetch a single item, to be run in parallel
|
|
700
|
-
item_data = self.cloud_manager.download_text_from_cloud(cloud_name(
|
|
701
|
-
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))
|
|
702
709
|
meta = json.loads(meta_data)
|
|
703
710
|
return index, build_return(item_data, meta, distance)
|
|
704
711
|
|
|
@@ -715,17 +722,17 @@ class Vault:
|
|
|
715
722
|
return [{'data': 'No data has been added', 'metadata': {'no meta': 'No metadata has been added'}}]
|
|
716
723
|
|
|
717
724
|
|
|
718
|
-
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):
|
|
719
726
|
'''
|
|
720
727
|
Returns similar items from the Vault as the one you entered, but locally
|
|
721
728
|
(saves a few milliseconds and is sometimes used on production builds)
|
|
722
729
|
'''
|
|
723
730
|
self.cloud_manager.update()
|
|
724
731
|
vector = self.process_batch([text], never_stop=False, loop_timeout=180)[0]
|
|
725
|
-
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)
|
|
726
733
|
|
|
727
734
|
|
|
728
|
-
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):
|
|
729
736
|
'''
|
|
730
737
|
Returns similar items from the Vault as the text you enter.
|
|
731
738
|
|
|
@@ -733,21 +740,21 @@ class Vault:
|
|
|
733
740
|
The distance can be useful for assessing similarity differences in the items returned.
|
|
734
741
|
Each item has its' own distance number, and this changes the structure of the output.
|
|
735
742
|
'''
|
|
736
|
-
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)
|
|
737
744
|
|
|
738
745
|
|
|
739
|
-
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):
|
|
740
747
|
"""
|
|
741
748
|
If your text length is greater than 15000 characters, you should use Vault.split_text(your_text) to
|
|
742
749
|
get a list of text segments that are the right size
|
|
743
750
|
"""
|
|
744
751
|
self.check_index()
|
|
745
|
-
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)
|
|
746
753
|
self.items.append(new_item)
|
|
747
754
|
self.add_to_map()
|
|
748
755
|
|
|
749
756
|
|
|
750
|
-
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):
|
|
751
758
|
"""
|
|
752
759
|
If your text length is greater than 4000 tokens, Vault.split_text(your_text)
|
|
753
760
|
will automatically be added
|
|
@@ -761,18 +768,19 @@ class Vault:
|
|
|
761
768
|
else:
|
|
762
769
|
texts = [text]
|
|
763
770
|
for text in texts:
|
|
764
|
-
self.add_item(text, meta, name)
|
|
771
|
+
self.add_item(text, meta, name, vault if vault else self.vault)
|
|
765
772
|
|
|
766
773
|
|
|
767
|
-
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):
|
|
768
775
|
"""
|
|
769
776
|
Adds data, gets vectors, then saves the data to the cloud in one call
|
|
770
777
|
If your text length is greater than 4000 tokens, your text will automatically be split by
|
|
771
778
|
Vault.split_text(your_text).
|
|
772
779
|
"""
|
|
773
|
-
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)
|
|
774
781
|
self.get_vectors()
|
|
775
|
-
self.save()
|
|
782
|
+
self.save(vault = vault if vault else self.vault)
|
|
783
|
+
T(target=self.clear_cache).start()
|
|
776
784
|
|
|
777
785
|
|
|
778
786
|
def add_item_with_vector(self, text: str, vector: list, meta: dict = None, name: str = None):
|
|
@@ -853,7 +861,7 @@ class Vault:
|
|
|
853
861
|
print("get vectors time --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
|
|
854
862
|
|
|
855
863
|
|
|
856
|
-
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,
|
|
857
865
|
n_context: int = 4, return_context: bool = False, history_search: bool = False, smart_history_search: bool = False,
|
|
858
866
|
model: str = 'gpt-3.5-turbo', include_context_meta: bool = False, custom_prompt: bool = False,
|
|
859
867
|
local: bool =False, temperature: int = 0, timeout: int = 300):
|
|
@@ -938,10 +946,11 @@ class Vault:
|
|
|
938
946
|
self.load_ai()
|
|
939
947
|
model = model.lower()
|
|
940
948
|
start_time = time.time()
|
|
941
|
-
|
|
942
|
-
if
|
|
943
|
-
|
|
944
|
-
|
|
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
|
+
|
|
945
954
|
if text:
|
|
946
955
|
inputs = [text]
|
|
947
956
|
else:
|
|
@@ -1006,12 +1015,13 @@ class Vault:
|
|
|
1006
1015
|
print(f"API Failed too many times, exiting loop: {e}.")
|
|
1007
1016
|
break
|
|
1008
1017
|
|
|
1018
|
+
self.update_conversation_history(self.cuid, response) if self.cuid else None
|
|
1009
1019
|
print("get chat time --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
|
|
1010
1020
|
|
|
1011
1021
|
return {'response': response, 'context': context} if return_context else response
|
|
1012
1022
|
|
|
1013
1023
|
|
|
1014
|
-
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,
|
|
1015
1025
|
n_context: int = 4, return_context: bool = False, history_search: bool = False, smart_history_search: bool = False,
|
|
1016
1026
|
model: str ='gpt-3.5-turbo', include_context_meta: bool = False, metatag: bool = False,
|
|
1017
1027
|
metatag_prefixes: bool = False, metatag_suffixes: bool = False, custom_prompt: bool = False,
|
|
@@ -1084,9 +1094,10 @@ class Vault:
|
|
|
1084
1094
|
self.load_ai()
|
|
1085
1095
|
model = model.lower()
|
|
1086
1096
|
start_time = time.time()
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
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
|
|
1090
1101
|
|
|
1091
1102
|
if text:
|
|
1092
1103
|
inputs = [text]
|
|
@@ -1100,7 +1111,7 @@ class Vault:
|
|
|
1100
1111
|
for segment in inputs:
|
|
1101
1112
|
start_time = time.time()
|
|
1102
1113
|
exceptions = 0
|
|
1103
|
-
|
|
1114
|
+
full_response = ''
|
|
1104
1115
|
while True:
|
|
1105
1116
|
try:
|
|
1106
1117
|
if summary and not get_context:
|
|
@@ -1116,6 +1127,7 @@ class Vault:
|
|
|
1116
1127
|
current_chunk = segment[start_index:end_index]
|
|
1117
1128
|
# Process the current chunk and concatenate the response
|
|
1118
1129
|
for word in self.ai.summarize_stream(current_chunk, model=model, custom_prompt=custom_prompt, temperature=temperature):
|
|
1130
|
+
full_response += word
|
|
1119
1131
|
yield word
|
|
1120
1132
|
yield ' '
|
|
1121
1133
|
|
|
@@ -1123,6 +1135,7 @@ class Vault:
|
|
|
1123
1135
|
except Exception as e:
|
|
1124
1136
|
raise e
|
|
1125
1137
|
if counter == len(inputs):
|
|
1138
|
+
self.update_conversation_history(self.cuid, full_response) if self.cuid else None
|
|
1126
1139
|
yield '!END'
|
|
1127
1140
|
self.rate_limiter.on_success()
|
|
1128
1141
|
|
|
@@ -1140,6 +1153,7 @@ class Vault:
|
|
|
1140
1153
|
|
|
1141
1154
|
try:
|
|
1142
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
|
|
1143
1157
|
yield word
|
|
1144
1158
|
self.rate_limiter.on_success()
|
|
1145
1159
|
except Exception as e:
|
|
@@ -1159,20 +1173,25 @@ class Vault:
|
|
|
1159
1173
|
for i in range(len(metatag)):
|
|
1160
1174
|
yield str(metatag_prefixes[i]) + str(item['metadata'][f'{metatag[i]}'])
|
|
1161
1175
|
yield item['data']
|
|
1176
|
+
self.update_conversation_history(self.cuid, full_response) if self.cuid else None
|
|
1162
1177
|
yield '!END'
|
|
1163
1178
|
self.rate_limiter.on_success()
|
|
1164
1179
|
else:
|
|
1180
|
+
self.update_conversation_history(self.cuid, full_response) if self.cuid else None
|
|
1165
1181
|
yield '!END'
|
|
1166
1182
|
self.rate_limiter.on_success()
|
|
1167
1183
|
|
|
1168
1184
|
else:
|
|
1169
1185
|
try:
|
|
1170
1186
|
for word in self.ai.llm_stream(segment, history, model=model, custom_prompt=custom_prompt, temperature=temperature):
|
|
1187
|
+
full_response += word
|
|
1171
1188
|
yield word
|
|
1172
1189
|
self.rate_limiter.on_success()
|
|
1173
1190
|
except Exception as e:
|
|
1174
1191
|
raise e
|
|
1192
|
+
self.update_conversation_history(self.cuid, full_response) if self.cuid else None
|
|
1175
1193
|
yield '!END'
|
|
1194
|
+
|
|
1176
1195
|
self.rate_limiter.on_success()
|
|
1177
1196
|
break
|
|
1178
1197
|
except Exception as e:
|
|
@@ -1252,6 +1271,83 @@ class Vault:
|
|
|
1252
1271
|
yield f"data: {json.dumps({'data': word})} \n\n"
|
|
1253
1272
|
|
|
1254
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
|
+
|
|
1255
1351
|
class RateLimiter:
|
|
1256
1352
|
def __init__(self, max_attempts=30):
|
|
1257
1353
|
self.base_delay = 1 # Base delay of 1 second
|
|
@@ -1267,4 +1363,4 @@ class RateLimiter:
|
|
|
1267
1363
|
def on_failure(self):
|
|
1268
1364
|
# Apply exponential backoff with a random jitter
|
|
1269
1365
|
self.current_delay = min(self.max_delay, random.uniform(self.base_delay, self.current_delay * self.backoff_factor))
|
|
1270
|
-
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
|