vector-vault 4.2.2__tar.gz → 4.2.4__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.2 → vector_vault-4.2.4}/PKG-INFO +1 -1
  2. {vector_vault-4.2.2 → vector_vault-4.2.4}/setup.py +1 -1
  3. {vector_vault-4.2.2 → vector_vault-4.2.4}/vector_vault.egg-info/PKG-INFO +1 -1
  4. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/ai.py +8 -8
  5. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/tools_gpt.py +82 -76
  6. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/vault.py +74 -54
  7. {vector_vault-4.2.2 → vector_vault-4.2.4}/LICENSE +0 -0
  8. {vector_vault-4.2.2 → vector_vault-4.2.4}/README.md +0 -0
  9. {vector_vault-4.2.2 → vector_vault-4.2.4}/setup.cfg +0 -0
  10. {vector_vault-4.2.2 → vector_vault-4.2.4}/vector_vault.egg-info/SOURCES.txt +0 -0
  11. {vector_vault-4.2.2 → vector_vault-4.2.4}/vector_vault.egg-info/dependency_links.txt +0 -0
  12. {vector_vault-4.2.2 → vector_vault-4.2.4}/vector_vault.egg-info/requires.txt +0 -0
  13. {vector_vault-4.2.2 → vector_vault-4.2.4}/vector_vault.egg-info/top_level.txt +0 -0
  14. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/__init__.py +0 -0
  15. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/cloud_api.py +0 -0
  16. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/cloudmanager.py +0 -0
  17. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/creds.py +0 -0
  18. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/download.py +0 -0
  19. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/itemize.py +0 -0
  20. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/vecreq.py +0 -0
  21. {vector_vault-4.2.2 → vector_vault-4.2.4}/vectorvault/wrap.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vector_vault
3
- Version: 4.2.2
3
+ Version: 4.2.4
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.2",
5
+ version="4.2.4",
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.2
3
+ Version: 4.2.4
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
@@ -7,8 +7,9 @@ import tempfile
7
7
  stock_sys_msg = "You are an AI assistant that excels at following instructions exactly."
8
8
 
9
9
  class AI:
10
- def __init__(self, personality_message: str = None, main_prompt: str = None, verbose: bool = False) -> None:
10
+ def __init__(self, personality_message: str = None, main_prompt: str = None, verbose: bool = False, timeout: int = 300) -> None:
11
11
  self.verbose = verbose
12
+ self.timeout = timeout
12
13
  self.model_token_limits = {
13
14
  'gpt-3.5-turbo': 16000,
14
15
  'gpt-3.5-turbo-0125': 16000,
@@ -50,8 +51,9 @@ class AI:
50
51
 
51
52
  return new_model
52
53
 
53
- def make_call(self, messages, model, temperature, timeout=45):
54
+ def make_call(self, messages, model, temperature, timeout=None):
54
55
  # This function will be run in a separate thread
56
+ timeout = self.timeout if not timeout else timeout
55
57
  def call_api(response_queue):
56
58
  try:
57
59
  response = openai.chat.completions.create(
@@ -76,18 +78,17 @@ class AI:
76
78
 
77
79
 
78
80
  # This function returns a ChatGPT completion based on a provided input
79
- def llm(self, user_input: str = '', history: str = '', model='gpt-3.5-turbo', max_tokens = 4000, custom_prompt = False, temperature = 0, timeout = 45, max_retries = 5):
81
+ def llm(self, user_input: str = '', history: str = '', model='gpt-3.5-turbo', max_tokens = 4000, custom_prompt = False, temperature = 0, timeout = None, max_retries = 5):
80
82
  '''
81
83
  If you pass in a custom_prompt, make sure you format your inputs - this function will not change it
82
84
  If you want a custom_prompt but also want to pass `user_input` to take advantage of this function's formatting, then save your custom prompt as default with `save_custom_prompt` in vault.py
83
85
  '''
86
+ timeout = self.timeout if not timeout else timeout
84
87
  prompt_template = custom_prompt if custom_prompt else self.prompt
85
88
 
86
89
  # Use token_model_check to select the suitable model based on token count
87
90
  model = self.model_check(self.get_tokens(history + user_input + prompt_template), model)
88
91
  max_tokens = self.model_token_limits.get(model, 4000)
89
- timeout = timeout * 2 if model in ['gpt-4-1106-preview','gpt-4-turbo-preview','gpt-4-0125-preview'] else timeout
90
- timeout = timeout * .67 if model in ['gpt-3.5-turbo','gpt-3.5-turbo-0125','gpt-3.5-turbo-16k'] else timeout
91
92
 
92
93
  if user_input:
93
94
  new_texts = self.truncate_text(user_input, history, prompt_template, max_tokens=max_tokens)
@@ -161,12 +162,11 @@ class AI:
161
162
  }]).choices[0].message.content
162
163
 
163
164
 
164
- def llm_w_context(self, user_input = '', context = '', history = '', model = 'gpt-3.5-turbo', max_tokens = 4000, custom_prompt = False, temperature = 0, timeout = 45, max_retries = 5):
165
+ def llm_w_context(self, user_input = '', context = '', history = '', model = 'gpt-3.5-turbo', max_tokens = 4000, custom_prompt = False, temperature = 0, timeout = None, max_retries = 5):
166
+ timeout = self.timeout if not timeout else timeout
165
167
  prompt_template = custom_prompt if custom_prompt else self.context_prompt
166
168
  model = self.model_check(self.get_tokens(history + user_input + prompt_template + context), model)
167
169
  max_tokens = self.model_token_limits.get(model, 4000)
168
- timeout = timeout * 2 if model in ['gpt-4-1106-preview','gpt-4-turbo-preview','gpt-4-0125-preview'] else timeout
169
- timeout = timeout * .67 if model in ['gpt-3.5-turbo','gpt-3.5-turbo-0125','gpt-3.5-turbo-16k'] else timeout
170
170
 
171
171
  if user_input and context:
172
172
  new_texts = self.truncate_text(user_input, history, prompt_template, context, max_tokens=max_tokens)
@@ -4,41 +4,43 @@ import ast
4
4
 
5
5
  '''
6
6
  ToolsGPT is a set of tools special to large language models.
7
- Every tool turns subjectivity into objectivity.
7
+ Every tool turns unstructured data into structured data.
8
8
 
9
- Objectivity is needed for code.
10
- Subjectivity is the primary human input.
11
- These tools bridge the gap between human interaction and code.
9
+ Structure data is required to run programs.
10
+ Unstructured data is the primary human output.
11
+ AI tools convert unstructured data into structured data,
12
+ bridging the gap between humans and programs.
13
+ Therefore, in the future, everything will be programmable.
12
14
 
13
15
  ToolsGPT allows you to get the following for any input:
14
16
  1. `get_rating` - returns a rating out of 10 for any input
15
17
  2. `get_yes_no` - returns a 'yes' or a 'no' to any question
16
- 3. `get_binary` - returns a '0' or '1' to any input
17
- 4. `get_match` - returns a match to a list options
18
- 5. `match_or_make` - returns a match to a list of options, or a new option
18
+ 3. `get_number` - returns an integer based on your instructions
19
+ 4. `get_match` - returns a match to a list options - (single choice)
20
+ 5. `get_multi_match` - returns one or many matches to a list of options - (multiple choice)
19
21
  6. `get_topic` - returns the topic subject matter of any input
20
22
 
21
23
  1. `get_rating`:
22
- Useful to get a quality rating
24
+ Get a numeric rating out of 10 for anything
23
25
 
24
26
  2. `get_yes_no`:
25
- Useful for getting a difinitive answer
27
+ Get an exact 'yes' or 'no' to any question
26
28
 
27
- 3. `get_binary`:
28
- Useful for getting a definitive answer in 0/1 format
29
+ 3. `get_number`:
30
+ Get an integer output for any input
29
31
 
30
32
  4. `get_match`:
31
- Useful to get an exact match to a single option within a set of options
33
+ Get an exact match to a single item within a list
34
+ -> in: (text and list of strings)
35
+ -> out: (one exact match to an answer in list -> string type)
36
+
37
+ 5. `get_multi_match`:
38
+ Get many matches to items within a list
32
39
  -> in: (text and list of answers)
33
- -> out: (exact match to one answer in list of answer)
40
+ -> out: (list of exact matches -> list type)
34
41
 
35
- 5. `get_topic`:
42
+ 6. `get_topic`:
36
43
  Useful to classify the topic of conversation
37
-
38
- 6. `match_or_make` (M&M):
39
- Get a match to a list of options, or make a new one if unrelated
40
- Useful if you aren't sure if the input will match one of your existing list options, and need flexibility of creating a new one
41
- Also useful when starting from an empty list. - will create it from scratch
42
44
  '''
43
45
 
44
46
  class ToolsGPT():
@@ -46,6 +48,7 @@ class ToolsGPT():
46
48
  self.verbose = verbose
47
49
  self.llm = AI(verbose=verbose).llm
48
50
 
51
+
49
52
  def get_rating(self, text: str = None, concept_to_rate_for: str = None, model='gpt-3.5-turbo', loop_limit=20) -> int:
50
53
  '''
51
54
  Get a numeric rating out of 10. Input plain text, and concept to rate for. Defualts to 'quality'
@@ -70,16 +73,25 @@ that this number has been carefully considered given your concept. My rating out
70
73
  try:
71
74
  return int(answer) # try to return an int zero shot
72
75
  except:
73
- return self.get_number(answer, model=model, loop_limit=loop_limit) # force the integer if zero shot fails
76
+ return self.retry_until_its_a_number(answer, model=model, loop_limit=loop_limit) # force the integer if zero shot fails
74
77
 
75
78
 
76
- def get_number(self, content: str, model='gpt-3.5-turbo', loop_limit=5) -> int:
79
+ def get_number(self, concept, content: str, model='gpt-3.5-turbo', loop_limit=5) -> int:
80
+ '''
81
+ param: `concept` - is the idea used to generate a number with - i.e. "How many students are in the professor's class?"
82
+ param: `content` - is the content to generate a number for - i.e. "I had 400 students in my class last year, but this year, I have 10% more."
83
+ '''
84
+ response = self.retry_llm(f'{concept} \n\n{content}', model=model, loop_limit=loop_limit)
85
+ print("Initial number extraction response:", response) if self.verbose else 0
86
+ return response if type(response) is int else self.retry_until_its_a_number(response, model=model, loop_limit=loop_limit)
87
+
88
+
89
+ def retry_until_its_a_number(self, content: str, model='gpt-3.5-turbo', loop_limit=5) -> int:
77
90
  '''
78
- Your content will be injected into this prompt:
79
- `...User: The following content should be a number - Content: "{content}"`
91
+ param: `content` - the AI will return an integer based on the content you input
80
92
  '''
81
- def retry_until_its_a_number(content):
82
- prompt_template = """Respond only with a number in integer format...
93
+
94
+ prompt_template = """Respond only with a number in integer format...
83
95
  Example content: 'The revenue for the last fiscal year was $1,200,000.' Example answer: '1200000'
84
96
  Example content 2: 'The company has been in business for twenty years.' Example answer 2: '20'
85
97
  Example content 3: 'The recipe calls for three cups of flour.' Example answer 3: '3'
@@ -90,27 +102,31 @@ Example content 7: 'The project deadline is in 45 days.' Example answer 7: '45'
90
102
  User: The following content should be a number - Content: "{content}"
91
103
  \nAgent:"""
92
104
 
93
- prompt = prompt_template.format(content=content)
94
- response = self.retry_llm(custom_prompt=prompt, model=model, loop_limit=loop_limit)
95
- if self.verbose:
96
- print("Extracted Number: ", response)
97
- return response
98
- loops = 0
99
- answer = content
100
- while True:
101
- if loops >= loop_limit:
102
- break
103
- answer = retry_until_its_a_number(answer)
104
- if self.verbose == True:
105
- print(f"Loops: {loops} | Number: {answer}")
106
- loops += 1
107
- try:
108
- answer = int(answer)
109
- break # finally exit loop when we get an integer
110
- except:
111
- pass
105
+ prompt = prompt_template.format(content=content)
106
+ response = self.retry_llm(custom_prompt=prompt, model=model, loop_limit=loop_limit)
107
+ print("Initial number extraction response:", response) if self.verbose else 0
108
+
109
+ if type(response) is int:
110
+ return response
111
+
112
+ else: # loop until its a number
113
+ loops = 0
114
+ answer = content
115
+
116
+ while True:
117
+ if loops >= loop_limit:
118
+ break
119
+
120
+ prompt = prompt_template.format(content=answer)
121
+ answer = self.retry_llm(custom_prompt=prompt, model=model, loop_limit=loop_limit)
122
+ print(f"Loops: {loops} | Number: {answer}") if self.verbose else 0
123
+
124
+ try:
125
+ answer = int(answer)
126
+ return answer # exit loop and return the integer
127
+ except:
128
+ loops += 1
112
129
 
113
- return answer # return the integer
114
130
 
115
131
  def get_yes_no(self, text: str, question: str = None, model='gpt-3.5-turbo', loop_limit=20) -> str:
116
132
  '''
@@ -118,36 +134,16 @@ User: The following content should be a number - Content: "{content}"
118
134
  Be sure to input text to get a yes or no to, then ask the question to answer
119
135
  '''
120
136
  answer = self.yay_or_nay(text, question, model=model) if question else self.yay_or_nay_question_in_content(text, model=model)
121
- if self.verbose == True:
122
- print(f"Y/N Initial Answer: {answer}")
123
-
137
+ print(f"Y/N Initial Answer: {answer}") if self.verbose == True else 0
138
+
124
139
  loops = 0
125
140
  while loops < loop_limit and answer not in ['yes', 'no']:
126
141
  answer = self.isolate_yes_no(answer)
127
- if self.verbose:
128
- print(f"Y/N Answer {loops}: {answer}")
142
+ print(f"Y/N Answer {loops}: {answer}") if self.verbose else 0
129
143
  loops += 1
130
144
 
131
145
  return answer
132
146
 
133
- def get_binary(self, text: str, zero_if: str, one_if: str, model='gpt-3.5-turbo', loop_limit=20) -> str:
134
- '''
135
- Get an exact "0" or "1" to any question, given an input.
136
- Input text to get a decision on, then tell why to pick 0 and why to pick 1.
137
- Prompt starts with "Repond '0' if"...
138
- '''
139
- answer = self.zero_or_one(text, zero_if, one_if, model=model)
140
- if self.verbose == True:
141
- print(f"0/1 Initial Answer: {answer}")
142
-
143
- loops = 0
144
- while loops < loop_limit and int(answer) not in [0, 1]:
145
- answer = self.isolate_zero_one(answer)
146
- if self.verbose:
147
- print(f"0/1 Answer {loops}: {answer}")
148
- loops += 1
149
-
150
- return int(answer)
151
147
 
152
148
  def get_match(self, text: str, list_of_options: list, model='gpt-3.5-turbo', loop_limit=4) -> str:
153
149
  '''
@@ -185,6 +181,7 @@ Content to classify: "{text}" \n\nDo not respond with anything other than the o
185
181
 
186
182
  return new_answer
187
183
 
184
+
188
185
  def get_multi_match(self, text: str, list_of_options: list, model='gpt-3.5-turbo', loop_limit=4) -> str:
189
186
  '''
190
187
  This function can be used in a variety of Natural Language Processing (NLP) tasks,
@@ -203,6 +200,7 @@ Content to classify: "{text}" \n\n Respond with a subset list that matches the
203
200
 
204
201
  return [i if i in list_of_options else self.get_match(i, list_of_options, model, loop_limit) for i in ast.literal_eval(answer)]
205
202
 
203
+
206
204
  def get_topic(self, text: str, list_of_options: list, model='gpt-3.5-turbo', loop_limit=4) -> str:
207
205
  '''
208
206
  Like get_match, default optimized for topic recognition
@@ -213,13 +211,11 @@ Content to classify: "{text}" \n\n Respond with a subset list that matches the
213
211
  list_copy.append(option.strip().replace('.', '').lower().strip('"').strip("'"))
214
212
  prompt_template = """Respond with one of the options on this list: {list_of_options}
215
213
  Content to classify: "{content}" \n\nClassifiy the content above based on which topic it is mostly related to one topic: {list_of_options}"""
214
+
216
215
  prompt = prompt_template.format(content=text, list_of_options=list_copy)
217
-
218
216
  topic = self.retry_llm_in_list(prompt, list_copy, model, loop_limit)
219
-
220
- if self.verbose:
221
- print(f"Topic Answer: {topic}")
222
-
217
+ print(f"Topic Answer: {topic}") if self.verbose else 0
218
+
223
219
  if topic is not None:
224
220
  topic = list_of_options[list_copy.index(topic)] # return original topic
225
221
 
@@ -268,6 +264,7 @@ Respond "Yes" if the right category already exists in the list'''
268
264
 
269
265
  return answer
270
266
 
267
+
271
268
  # internal function
272
269
  def make_option(self, text, list_of_options: list, model='gpt-3.5-turbo') -> str:
273
270
  prompt_template = """Content to classify: "{content}" \n\n
@@ -277,6 +274,7 @@ Create a new category for the content based on these other categories in this li
277
274
 
278
275
  return self.retry_llm(custom_prompt=prompt, model=model)
279
276
 
277
+
280
278
  # internal function
281
279
  def make_option_from_zero(self, text, model='gpt-3.5-turbo'):
282
280
  '''
@@ -290,6 +288,7 @@ no explination before or after, just the name of the catagory. \n\nThe name of t
290
288
 
291
289
  return self.retry_llm(custom_prompt=prompt, model=model)
292
290
 
291
+
293
292
  # internal function
294
293
  def finalize_category(self, text, prev_answer):
295
294
  prompt_template = """Given the following category suggestion: "{prev_answer}"
@@ -299,6 +298,7 @@ no explination before or after, just the name of the catagory. \n\nThe name of t
299
298
 
300
299
  return self.retry_llm(custom_prompt=prompt)
301
300
 
301
+
302
302
  # internal function
303
303
  def isolate_yes_no(self, content, question: str, model='gpt-3.5-turbo'):
304
304
  '''Not recommended for external use. Internal function'''
@@ -313,6 +313,7 @@ Example question 5: 'Will this happen if it's 19 percent likely to happen?' Exam
313
313
 
314
314
  return self.retry_llm(custom_prompt=prompt, model=model)
315
315
 
316
+
316
317
  # internal function
317
318
  def yay_or_nay(self, content, question: str, model='gpt-3.5-turbo'):
318
319
  '''Not recommended for external use. Internal function'''
@@ -327,6 +328,7 @@ Example question 5: 'Will this happen if it's 19 percent likely to happen?' Exam
327
328
 
328
329
  return self.retry_llm(custom_prompt=prompt, model=model)
329
330
 
331
+
330
332
  # internal function
331
333
  def yay_or_nay_question_in_content(self, content: str, model='gpt-3.5-turbo'):
332
334
  '''Not recommended for external use. Internal function'''
@@ -344,6 +346,7 @@ Agent:"""
344
346
 
345
347
  return self.retry_llm(custom_prompt=prompt, model=model)
346
348
 
349
+
347
350
  # internal function
348
351
  def zero_or_one(self, content, zero_if: str, one_if: str, model='gpt-3.5-turbo'):
349
352
  '''Not recommended for external use. Internal function'''
@@ -358,6 +361,7 @@ Example question 5: 'Will this happen if it's 19 percent likely to happen?' Exam
358
361
 
359
362
  return self.retry_llm(custom_prompt=prompt, model=model)
360
363
 
364
+
361
365
  # internal function
362
366
  def isolate_zero_one(self, content, model='gpt-3.5-turbo'):
363
367
  '''Not recommended for external use. Internal function'''
@@ -372,6 +376,7 @@ Example question 5: 'Will this happen if it's 19 percent likely to happen?' Exam
372
376
 
373
377
  return self.retry_llm(custom_prompt=prompt, model=model)
374
378
 
379
+
375
380
  # This function is called by the others to handle retries:
376
381
  def retry_llm(self, custom_prompt, model='gpt-3.5-turbo', loop_limit=2, temperature=0):
377
382
  for i in range(loop_limit):
@@ -383,11 +388,12 @@ Example question 5: 'Will this happen if it's 19 percent likely to happen?' Exam
383
388
  print(f"Attempt {i+1} failed with error: {str(e)}. Retrying...")
384
389
  else:
385
390
  raise f"Attempt {i+1} failed with error: {str(e)}. No more retries."
386
-
391
+
392
+
387
393
  def perfect(self, content, instructions: str, model='gpt-3.5-turbo'):
388
394
  '''Wrapper function ensures that you get exactly what you wanted, and will not return until you get what you wanted'''
389
- output = self.get_yes_no(model=model, text=f"These are the instructions: {instructions}",
390
- question=f"This is the Output: {content} \n\nDoes this output match the instructions?", ) == 'no'
395
+ output = self.get_yes_no(model=model, text=f"These are the instructions: {instructions} and this is the Output: {content}",
396
+ question=f"Does the output match the instructions?", ) == 'no'
391
397
 
392
398
  while output:
393
399
  new_intstructions = f'''The following content does not match the instructions exactly. Your job is to return the content exactly as the instructions direct:
@@ -96,16 +96,18 @@ class Vault:
96
96
  self.rate_limiter = RateLimiter(max_attempts=30)
97
97
  t.join()
98
98
 
99
+
99
100
  def connect_to_cloud(self):
100
101
  try:
101
102
  self.cloud_manager = CloudManager(self.user, self.api, self.vault)
102
- if self.verbose:
103
- print(f'Connected vault: {self.vault}')
103
+ print(f'Connected vault: {self.vault}') if self.verbose else 0
104
+
104
105
  except Exception as e:
105
106
  print('API KEY NOT FOUND or no internet connection!', e)
106
107
  # user can still use the get_chat() function without an api key
107
108
  self.cloud_manager = None
108
109
 
110
+
109
111
  def get_vaults(self, vault: str = None):
110
112
  '''
111
113
  Returns a list of vaults within the current vault directory
@@ -113,6 +115,7 @@ class Vault:
113
115
  vault = self.vault if vault is None else vault
114
116
  return self.cloud_manager.list_vaults(vault)
115
117
 
118
+
116
119
  def get_total_items(self, vault: str = None):
117
120
  '''
118
121
  Returns the total number of vectored items in the Vault
@@ -130,6 +133,7 @@ class Vault:
130
133
  except: # it doesn't exist
131
134
  return 0
132
135
 
136
+
133
137
  def get_tokens(self, text: str):
134
138
  '''
135
139
  Returns the number of tokens for any given text
@@ -137,6 +141,7 @@ class Vault:
137
141
  self.load_ai()
138
142
  return self.ai.get_tokens(text)
139
143
 
144
+
140
145
  def get_distance(self, id1: int, id2: int):
141
146
  '''
142
147
  Returns the distance between two vectors - item ids are needed to compare
@@ -144,6 +149,7 @@ class Vault:
144
149
  self.check_index()
145
150
  return self.vectors.get_distance(id1, id2)
146
151
 
152
+
147
153
  def get_item_vector(self, item_id: int):
148
154
  '''
149
155
  Returns the vector from an item id
@@ -151,6 +157,7 @@ class Vault:
151
157
  self.check_index()
152
158
  return self.vectors.get_item_vector(item_id)
153
159
 
160
+
154
161
  def load_ai(self):
155
162
  self.ai_loaded = True
156
163
  self.ai = AI(verbose=self.verbose)
@@ -158,15 +165,16 @@ class Vault:
158
165
  self.ai.prompt = self.fetch_custom_prompt(context=False)
159
166
  self.ai.personality_message = self.fetch_personality_message()
160
167
 
168
+
161
169
  def save_personality_message(self, text: str):
162
170
  '''
163
171
  Saves personality_message to the vault and use it by default from now on
164
172
  '''
165
173
  self.cloud_manager.upload_personality_message(text)
166
174
 
167
- if self.verbose:
168
- print(f"Personality message saved")
169
-
175
+ print(f"Personality message saved") if self.verbose else 0
176
+
177
+
170
178
  def fetch_personality_message(self):
171
179
  '''
172
180
  Retrieves personality_message from the vault if it is there or else use the defualt
@@ -182,6 +190,7 @@ class Vault:
182
190
 
183
191
  return personality_message
184
192
 
193
+
185
194
  def save_custom_prompt(self, text: str, context=True):
186
195
  '''
187
196
  Saves custom_prompt to the vault and use it by default from now on
@@ -189,9 +198,9 @@ class Vault:
189
198
  '''
190
199
  self.cloud_manager.upload_custom_prompt(text) if context else self.cloud_manager.upload_no_context_prompt(text)
191
200
 
192
- if self.verbose:
193
- print(f"Custom prompt saved")
194
-
201
+ print(f"Custom prompt saved") if self.verbose else 0
202
+
203
+
195
204
  def fetch_custom_prompt(self, context=True):
196
205
  '''
197
206
  Retrieves custom_prompt from the vault if there or eles use defualt - (used for get_context = True responses)
@@ -208,6 +217,7 @@ class Vault:
208
217
 
209
218
  return prompt
210
219
 
220
+
211
221
  def save(self, trees: int = 10):
212
222
  '''
213
223
  Saves all the data added locally to the Cloud. All Vault references are Cloud references.
@@ -229,10 +239,9 @@ class Vault:
229
239
  total_saved_items += 1
230
240
 
231
241
  self.upload_vectors()
232
-
233
- if self.verbose:
234
- print(f"upload time --- {(time.time() - start_time)} seconds --- {total_saved_items} items saved")
242
+ print(f"upload time --- {(time.time() - start_time)} seconds --- {total_saved_items} items saved") if self.verbose else 0
235
243
 
244
+
236
245
  def clear_cache(self):
237
246
  '''
238
247
  Clears the cache for all the loaded items
@@ -242,12 +251,13 @@ class Vault:
242
251
  self.vecs_loaded = True
243
252
  self.saved_already = False
244
253
 
254
+
245
255
  def delete(self):
246
256
  '''
247
257
  Deletes the entire Vault and all contents
248
258
  '''
249
- if self.verbose:
250
- print('Deleting started. Note: this can take a while for large datasets')
259
+ print('Deleting started. Note: this can take a while for large datasets') if self.verbose else 0
260
+
251
261
  # Clear the local vector data
252
262
  self.vectors = get_vectors(self.dims)
253
263
  self.items.clear()
@@ -255,11 +265,13 @@ class Vault:
255
265
  self.x = 0
256
266
  print('Vault deleted')
257
267
 
268
+
258
269
  def remap(self, item_id):
259
270
  for i in range(item_id, len(self.map) - 1):
260
271
  self.map[str(i)] = self.map[str(i + 1)]
261
272
  self.map.popitem()
262
273
 
274
+
263
275
  def update_vault_data(self):
264
276
  nary = []
265
277
  try:
@@ -296,6 +308,7 @@ class Vault:
296
308
 
297
309
  self.cloud_manager.upload_temp_file(nary_temp_file_path, f'{self.cloud_manager.username}.json')
298
310
 
311
+
299
312
  def delete_items(self, item_ids: List[int], trees: int = 10) -> None:
300
313
  '''
301
314
  Deletes one or more items from item_id(s) passed in.
@@ -334,8 +347,8 @@ class Vault:
334
347
  self.remap(item_id)
335
348
  rebuild_vectors(item_id)
336
349
 
337
- if self.verbose:
338
- print(f'Item {item_id} deleted')
350
+ print(f'Item {item_id} deleted') if self.verbose else 0
351
+
339
352
 
340
353
  def edit_item(self, item_id: int, new_text: str, trees: int = 10) -> None:
341
354
  '''
@@ -362,17 +375,16 @@ class Vault:
362
375
  self.cloud_manager.upload_to_cloud(cloud_name(self.vault, self.map[str(item_id)], self.user, self.api, item=True), new_text)
363
376
  edit_vector(item_id, self.process_batch([new_text], never_stop=False, loop_timeout=180)[0])
364
377
 
365
- if self.verbose:
366
- print(f'Item {item_id} edited')
378
+ print(f'Item {item_id} edited') if self.verbose else 0
379
+
367
380
 
368
381
  def edit_item_meta(self, item_id: int, metadata) -> None:
369
382
  '''
370
383
  Edit and save any item's metadata
371
384
  '''
372
385
  self.cloud_manager.upload_to_cloud(cloud_name(self.vault, self.map[str(item_id)], self.user, self.api, meta=True), json.dumps(metadata))
386
+ print(f'Item {item_id} metadata saved') if self.verbose else 0
373
387
 
374
- if self.verbose:
375
- print(f'Item {item_id} metadata saved')
376
388
 
377
389
  def check_index(self):
378
390
  if not self.x_checked:
@@ -383,8 +395,8 @@ class Vault:
383
395
  self.reload_vectors()
384
396
 
385
397
  self.x_checked = True
386
- if self.verbose:
387
- print("initialize index --- %s seconds ---" % (time.time() - start_time))
398
+ print("initialize index --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
399
+
388
400
 
389
401
  def load_mapping(self):
390
402
  '''Internal function only'''
@@ -401,6 +413,7 @@ class Vault:
401
413
  self.map[str(self.x)] = str(uuid.uuid4())
402
414
  self.x +=1
403
415
 
416
+
404
417
  def load_vectors(self):
405
418
  start_time = time.time()
406
419
  t = T(target=self.load_mapping())
@@ -410,8 +423,8 @@ class Vault:
410
423
  os.remove(temp_file_path)
411
424
  t.join()
412
425
  self.vecs_loaded = True
413
- if self.verbose:
414
- print("get load vectors --- %s seconds ---" % (time.time() - start_time))
426
+ print("get load vectors --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
427
+
415
428
 
416
429
  def make_3d_map(self, highlight_id: int = None, return_html: bool = False):
417
430
  from kneed import KneeLocator
@@ -509,6 +522,7 @@ class Vault:
509
522
  else:
510
523
  fig.show()
511
524
 
525
+
512
526
  def reload_vectors(self):
513
527
  num_existing_items = self.vectors.get_n_items()
514
528
  new_index = get_vectors(self.dims)
@@ -520,6 +534,7 @@ class Vault:
520
534
  self.x = count + 1
521
535
  self.vectors = new_index
522
536
 
537
+
523
538
  def upload_vectors(self):
524
539
  with tempfile.NamedTemporaryFile(delete=False) as temp_file:
525
540
  vector_temp_file_path = temp_file.name
@@ -542,6 +557,7 @@ class Vault:
542
557
  self.vecs_loaded = False
543
558
  self.saved_already = False
544
559
 
560
+
545
561
  def split_text(self, text: str, min_threshold: int = 1000, max_threshold: int = 16000):
546
562
  '''
547
563
  Internal function
@@ -584,11 +600,11 @@ class Vault:
584
600
  if current_segment and (current_length >= min_threshold or not segments):
585
601
  segments.append(" ".join(current_segment))
586
602
 
587
- if self.verbose:
588
- print(f'split_text chunks: {len(segments)}')
603
+ print(f'split_text chunks: {len(segments)}') if self.verbose else 0
589
604
 
590
605
  return segments
591
606
 
607
+
592
608
  def get_items(self, ids: List[int] = [], vault: str = None) -> list:
593
609
  '''
594
610
  Get one or more items from the database.
@@ -641,11 +657,11 @@ class Vault:
641
657
  index, result = future.result()
642
658
  results[index] = result # Insert each result at its corresponding index
643
659
 
644
- if self.verbose:
645
- print(f"Retrieved {len(ids)} items --- %s seconds ---" % (time.time() - start_time))
646
-
660
+ print(f"Retrieved {len(ids)} items --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
661
+
647
662
  return results
648
663
 
664
+
649
665
  def get_items_by_vector(self, vector: list, n: int = 4, include_distances: bool = False):
650
666
  '''
651
667
  Internal function that returns vector similar items. Requires input vector, returns similar items
@@ -670,8 +686,8 @@ class Vault:
670
686
  index, result = future.result()
671
687
  results[index] = result # Insert each result at its corresponding index
672
688
 
673
- if self.verbose:
674
- print(f"get {n} items back --- %s seconds ---" % (time.time() - start_time))
689
+ print(f"get {n} items back --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
690
+
675
691
  return results
676
692
  else:
677
693
  vecs, distances = self.vectors.get_nns_by_vector(vector, n, include_distances=include_distances)
@@ -690,12 +706,13 @@ class Vault:
690
706
  index, result = future.result()
691
707
  results[index] = result # Insert each result at its corresponding index
692
708
 
693
- if self.verbose:
694
- print(f"get {n} items back --- %s seconds ---" % (time.time() - start_time))
709
+ print(f"get {n} items back --- %s seconds ---" % (time.time() - start_time))if self.verbose else 0
710
+
695
711
  return results
696
712
  except:
697
713
  return [{'data': 'No data has been added', 'metadata': {'no meta': 'No metadata has been added'}}]
698
714
 
715
+
699
716
  def get_similar_local(self, text: str, n: int = 4, include_distances: bool = False):
700
717
  '''
701
718
  Returns similar items from the Vault as the one you entered, but locally
@@ -705,6 +722,7 @@ class Vault:
705
722
  vector = self.process_batch([text], never_stop=False, loop_timeout=180)[0]
706
723
  return self.get_items_by_vector(vector, n, include_distances=include_distances)
707
724
 
725
+
708
726
  def get_similar(self, text: str, n: int = 4, include_distances: bool = False):
709
727
  '''
710
728
  Returns similar items from the Vault as the text you enter.
@@ -712,11 +730,10 @@ class Vault:
712
730
  Param `include_distances = True` adds the "distance" field to the return.
713
731
  The distance can be useful for assessing similarity differences in the items returned.
714
732
  Each item has its' own distance number, and this changes the structure of the output.
715
-
716
-
717
733
  '''
718
734
  return call_get_similar(self.user, self.vault, self.api, self.openai_key, text, n, include_distances=include_distances, verbose=self.verbose)
719
735
 
736
+
720
737
  def add_item(self, text: str, meta: dict = None, name: str = None):
721
738
  """
722
739
  If your text length is greater than 15000 characters, you should use Vault.split_text(your_text) to
@@ -727,6 +744,7 @@ class Vault:
727
744
  self.items.append(new_item)
728
745
  self.add_to_map()
729
746
 
747
+
730
748
  def add(self, text: str, meta: dict = None, name: str = None, split: bool = False, split_size: int = 1000, max_threshold: int = 16000):
731
749
  """
732
750
  If your text length is greater than 4000 tokens, Vault.split_text(your_text)
@@ -735,14 +753,15 @@ class Vault:
735
753
  self.check_index()
736
754
 
737
755
  if len(text) > 15000 or split:
738
- if self.verbose:
739
- print('Using the built-in "split_text()" function to get a list of texts')
756
+ print('Using the built-in "split_text()" function to get a list of texts') if self.verbose else 0
757
+
740
758
  texts = self.split_text(text, min_threshold=split_size, max_threshold=max_threshold) # returns list of text segments
741
759
  else:
742
760
  texts = [text]
743
761
  for text in texts:
744
762
  self.add_item(text, meta, name)
745
763
 
764
+
746
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):
747
766
  """
748
767
  Adds data, gets vectors, then saves the data to the cloud in one call
@@ -753,6 +772,7 @@ class Vault:
753
772
  self.get_vectors()
754
773
  self.save()
755
774
 
775
+
756
776
  def add_item_with_vector(self, text: str, vector: list, meta: dict = None, name: str = None):
757
777
  """
758
778
  If your text length is greater than 15000 characters, you should use Vault.split_text(your_text) to
@@ -769,9 +789,9 @@ class Vault:
769
789
  self.items.append(itemize(self.vault, self.x, meta, text, name))
770
790
  self.add_to_map()
771
791
 
772
- if self.verbose:
773
- print("add item time --- %s seconds ---" % (time.time() - start_time))
774
-
792
+ print("add item time --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
793
+
794
+
775
795
  def process_batch(self, batch_text_chunks, never_stop, loop_timeout):
776
796
  '''
777
797
  Internal function
@@ -799,9 +819,10 @@ class Vault:
799
819
  raise TimeoutError("Loop timed out")
800
820
  return [record.embedding for record in res.data]
801
821
 
822
+
802
823
  def get_vectors(self, batch_size: int = 32, never_stop: bool = False, loop_timeout: int = 777):
803
824
  '''
804
- Takes text data added to the vault, and gets vectors for them
825
+ Takes text data added to the vault, and gets vectors for them
805
826
  '''
806
827
  self.check_index()
807
828
  start_time = time.time()
@@ -827,14 +848,13 @@ class Vault:
827
848
  current_item_index += 1
828
849
 
829
850
  self.last_time = time.time()
830
- if self.verbose:
831
- print("get vectors time --- %s seconds ---" % (time.time() - start_time))
832
-
851
+ print("get vectors time --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
852
+
833
853
 
834
854
  def get_chat(self, text: str = None, history: str = None, summary: bool = False, get_context: bool = False,
835
855
  n_context: int = 4, return_context: bool = False, history_search: bool = False, smart_history_search: bool = False,
836
856
  model: str = 'gpt-3.5-turbo', include_context_meta: bool = False, custom_prompt: bool = False,
837
- local: bool =False, temperature: int = 0, timeout: int = 45):
857
+ local: bool =False, temperature: int = 0, timeout: int = 300):
838
858
  '''
839
859
  Chat get response from OpenAI's ChatGPT.
840
860
  Models: ChatGPT = "gpt-3.5-turbo" • GPT4 = "gpt-4"
@@ -984,19 +1004,16 @@ class Vault:
984
1004
  print(f"API Failed too many times, exiting loop: {e}.")
985
1005
  break
986
1006
 
987
- if self.verbose:
988
- print("get chat time --- %s seconds ---" % (time.time() - start_time))
989
-
990
- if not return_context:
991
- return response
992
- elif return_context:
993
- return {'response': response, 'context': context}
1007
+ print("get chat time --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
1008
+
1009
+ return {'response': response, 'context': context} if return_context else response
994
1010
 
1011
+
995
1012
  def get_chat_stream(self, text: str = None, history: str = None, summary: bool = False, get_context: bool = False,
996
1013
  n_context: int = 4, return_context: bool = False, history_search: bool = False, smart_history_search: bool = False,
997
1014
  model: str ='gpt-3.5-turbo', include_context_meta: bool = False, metatag: bool = False,
998
1015
  metatag_prefixes: bool = False, metatag_suffixes: bool = False, custom_prompt: bool = False,
999
- local: bool = False, temperature: int = 0, timeout: int = 45):
1016
+ local: bool = False, temperature: int = 0, timeout: int = 300):
1000
1017
  '''
1001
1018
  Always use this get_chat_stream() wrapped by either print_stream(), or cloud_stream().
1002
1019
  cloud_stream() is for cloud functions, like a flask app serving a front end elsewhere.
@@ -1164,8 +1181,8 @@ class Vault:
1164
1181
  print(f"API Failed too many times, exiting loop: {e}.")
1165
1182
  break
1166
1183
 
1167
- if self.verbose:
1168
- print("get chat time --- %s seconds ---" % (time.time() - start_time))
1184
+ print("get chat time --- %s seconds ---" % (time.time() - start_time)) if self.verbose else 0
1185
+
1169
1186
 
1170
1187
  def print_stream(self, function, printing=True):
1171
1188
  '''
@@ -1185,6 +1202,7 @@ class Vault:
1185
1202
  else:
1186
1203
  return full_text
1187
1204
 
1205
+
1188
1206
  def print_vault_data(self, print_data: bool = True, return_data: bool = False):
1189
1207
  '''
1190
1208
  Function to print vault data
@@ -1223,6 +1241,7 @@ class Vault:
1223
1241
 
1224
1242
  return vd if return_data else None
1225
1243
 
1244
+
1226
1245
  def cloud_stream(self, function):
1227
1246
  '''
1228
1247
  For cloud application yielding the chat stream, like a flask app
@@ -1230,6 +1249,7 @@ class Vault:
1230
1249
  for word in function:
1231
1250
  yield f"data: {json.dumps({'data': word})} \n\n"
1232
1251
 
1252
+
1233
1253
  class RateLimiter:
1234
1254
  def __init__(self, max_attempts=30):
1235
1255
  self.base_delay = 1 # Base delay of 1 second
File without changes
File without changes
File without changes