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.
Files changed (21) hide show
  1. {vector_vault-4.2.5 → vector_vault-4.2.7}/PKG-INFO +1 -1
  2. {vector_vault-4.2.5 → vector_vault-4.2.7}/setup.py +1 -1
  3. {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/PKG-INFO +1 -1
  4. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/cloudmanager.py +8 -17
  5. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/itemize.py +25 -1
  6. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/tools_gpt.py +1 -1
  7. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/vault.py +144 -48
  8. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/vecreq.py +28 -0
  9. {vector_vault-4.2.5 → vector_vault-4.2.7}/LICENSE +0 -0
  10. {vector_vault-4.2.5 → vector_vault-4.2.7}/README.md +0 -0
  11. {vector_vault-4.2.5 → vector_vault-4.2.7}/setup.cfg +0 -0
  12. {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/SOURCES.txt +0 -0
  13. {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/dependency_links.txt +0 -0
  14. {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/requires.txt +0 -0
  15. {vector_vault-4.2.5 → vector_vault-4.2.7}/vector_vault.egg-info/top_level.txt +0 -0
  16. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/__init__.py +0 -0
  17. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/ai.py +0 -0
  18. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/cloud_api.py +0 -0
  19. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/creds.py +0 -0
  20. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/download.py +0 -0
  21. {vector_vault-4.2.5 → vector_vault-4.2.7}/vectorvault/wrap.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vector_vault
3
- Version: 4.2.5
3
+ Version: 4.2.7
4
4
  Summary: Quickly create ChatGPT RAG apps and Unleash the full potential of GenAI with Vector Vault
5
5
  Home-page: https://github.com/John-Rood/VectorVault
6
6
  Author: VectorVault.io
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="vector_vault",
5
- version="4.2.5",
5
+ version="4.2.7",
6
6
  packages=find_packages(),
7
7
  author="VectorVault.io",
8
8
  author_email="john@johnrood.com",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vector-vault
3
- Version: 4.2.5
3
+ Version: 4.2.7
4
4
  Summary: Quickly create ChatGPT RAG apps and Unleash the full potential of GenAI with Vector Vault
5
5
  Home-page: https://github.com/John-Rood/VectorVault
6
6
  Author: VectorVault.io
@@ -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, T as t, time, json, os, tempfile
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
- th = t(target=call_update, args=(self.user, self.vault, self.api))
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
@@ -1,4 +1,4 @@
1
- from .ai import AI
1
+ from ai import AI
2
2
  import time
3
3
  import ast
4
4
 
@@ -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 .cloudmanager import CloudManager
28
+ from datetime import datetime, timedelta
29
+ from concurrent.futures import ThreadPoolExecutor, as_completed
31
30
  from .ai import AI, openai
32
- from .itemize import itemize, name_vecs, get_item, get_vectors, build_return, cloud_name, name_map
33
- from .vecreq import call_get_similar
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, vault: str = None, openai_key: str = None, embeddings_model: str = None, verbose: bool = False):
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(self.vault, self.user, self.api))
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(self.vault, self.user, self.api)): # but if the vault does
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(self.vault, self.user, self.api))
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(self.vault, self.user, self.api, byte))
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(self.vault, self.user, self.api, byte))
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.load_vectors()
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(self.vault, self.map[str(vec)], self.user, self.api, item=True))
681
- meta_data = self.cloud_manager.download_text_from_cloud(cloud_name(self.vault, self.map[str(vec)], self.user, self.api, meta=True))
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(self.vault, self.map[str(vec)], self.user, self.api, item=True))
701
- meta_data = self.cloud_manager.download_text_from_cloud(cloud_name(self.vault, self.map[str(vec)], self.user, self.api, meta=True))
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 = None, summary: bool = False, get_context: bool = False,
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 not history:
943
- history = ''
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 = None, summary: bool = False, get_context: bool = False,
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
- if not history:
1089
- history = ''
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