rohan13 commited on
Commit
aad01e3
β€’
1 Parent(s): 7515dcf

removing agent implementation to optimize speed

Browse files
Files changed (6) hide show
  1. app.py +7 -2
  2. main.py +3 -27
  3. main_old.py +34 -0
  4. requirements.txt +4 -3
  5. utils.py +34 -163
  6. utils_old.py +271 -0
app.py CHANGED
@@ -1,13 +1,13 @@
1
  import gradio as gr
2
  from main import index, run
3
  from gtts import gTTS
4
- import os
5
 
6
  from transformers import pipeline
7
 
8
  p = pipeline("automatic-speech-recognition")
9
 
10
- """Use text to call chat method from main.py"""
11
  def add_text(history, text):
12
  print("Question asked: " + text)
13
  response = run_model(text)
@@ -17,11 +17,16 @@ def add_text(history, text):
17
 
18
 
19
  def run_model(text):
 
 
20
  response = run(question=text)
 
21
  # If response contains string `SOURCES:`, then add a \n before `SOURCES`
22
  if "SOURCES:" in response:
23
  response = response.replace("SOURCES:", "\nSOURCES:")
 
24
  print(response)
 
25
  return response
26
 
27
 
 
1
  import gradio as gr
2
  from main import index, run
3
  from gtts import gTTS
4
+ import os, time
5
 
6
  from transformers import pipeline
7
 
8
  p = pipeline("automatic-speech-recognition")
9
 
10
+ """Use text to call chat method from main_old.py"""
11
  def add_text(history, text):
12
  print("Question asked: " + text)
13
  response = run_model(text)
 
17
 
18
 
19
  def run_model(text):
20
+ start_time = time.time()
21
+ print("start time:" + str(start_time))
22
  response = run(question=text)
23
+ end_time = time.time()
24
  # If response contains string `SOURCES:`, then add a \n before `SOURCES`
25
  if "SOURCES:" in response:
26
  response = response.replace("SOURCES:", "\nSOURCES:")
27
+ # response = response + "\n\n" + "Time taken: " + str(end_time - start_time)
28
  print(response)
29
+ print("Time taken: " + str(end_time - start_time))
30
  return response
31
 
32
 
main.py CHANGED
@@ -1,33 +1,9 @@
1
- from utils import create_index, get_agent_chain, get_prompt_and_tools, get_search_index
2
- from utils import get_custom_agent, get_prompt_and_tools_for_custom_agent
3
- question_starters = ['who', 'why', 'what', 'how', 'where', 'when', 'which', 'whom', 'whose']
4
-
5
 
6
  def index():
7
  get_search_index()
8
  return True
9
 
10
  def run(question):
11
- index = get_search_index()
12
-
13
- # prompt, tools = get_prompt_and_tools()
14
-
15
- # agent_chain = get_agent_chain(prompt, tools)
16
-
17
- prompt, tools = get_prompt_and_tools_for_custom_agent()
18
-
19
- agent_chain = get_custom_agent(prompt, tools)
20
-
21
- result = None
22
-
23
- try:
24
- result = agent_chain.run(question)
25
- except ValueError as ve:
26
- if "Could not parse LLM output:" in ve.args[0] and question.lower().startswith(tuple(question_starters)) and not question.lower().endswith('?'):
27
- question = question + '?'
28
- result = agent_chain.run(question)
29
- finally:
30
- print(result)
31
-
32
- return result
33
-
 
1
+ from utils import get_search_index, get_qa_chain, generate_answer
 
 
 
2
 
3
  def index():
4
  get_search_index()
5
  return True
6
 
7
  def run(question):
8
+ index()
9
+ return generate_answer(question)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
main_old.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from utils_old import get_custom_agent, get_prompt_and_tools_for_custom_agent
2
+ from utils_old import get_search_index
3
+
4
+ question_starters = ['who', 'why', 'what', 'how', 'where', 'when', 'which', 'whom', 'whose']
5
+
6
+
7
+ def index():
8
+ get_search_index()
9
+ return True
10
+
11
+ def run(question):
12
+ index = get_search_index()
13
+
14
+ # prompt, tools = get_prompt_and_tools()
15
+
16
+ # agent_chain = get_agent_chain(prompt, tools)
17
+
18
+ prompt, tools = get_prompt_and_tools_for_custom_agent()
19
+
20
+ agent_chain = get_custom_agent(prompt, tools)
21
+
22
+ result = None
23
+
24
+ try:
25
+ result = agent_chain.run(question)
26
+ except ValueError as ve:
27
+ if "Could not parse LLM output:" in ve.args[0] and question.lower().startswith(tuple(question_starters)) and not question.lower().endswith('?'):
28
+ question = question + '?'
29
+ result = agent_chain.run(question)
30
+ finally:
31
+ print(result)
32
+
33
+ return result
34
+
requirements.txt CHANGED
@@ -1,8 +1,9 @@
1
- langchain==0.0.131
2
- openai==0.27.2
3
  faiss-cpu==1.7.3
4
  unstructured==0.5.8
5
  ffmpeg-python
6
  transformers
7
  gtts
8
- torch
 
 
1
+ langchain==0.0.166
2
+ openai
3
  faiss-cpu==1.7.3
4
  unstructured==0.5.8
5
  ffmpeg-python
6
  transformers
7
  gtts
8
+ torch
9
+ tiktoken
utils.py CHANGED
@@ -1,27 +1,31 @@
1
  import os
2
  import pickle
3
- import re
4
- from typing import List, Union
5
 
6
  import faiss
7
- from langchain import OpenAI, LLMChain
8
- from langchain.agents import ConversationalAgent
9
- from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser
10
  from langchain.chains import ConversationalRetrievalChain
 
11
  from langchain.document_loaders import DirectoryLoader, TextLoader, UnstructuredHTMLLoader
12
  from langchain.embeddings import OpenAIEmbeddings
13
  from langchain.memory import ConversationBufferWindowMemory
14
- from langchain.prompts import BaseChatPromptTemplate
15
- from langchain.schema import AgentAction, AgentFinish, HumanMessage
 
 
 
16
  from langchain.text_splitter import CharacterTextSplitter
17
  from langchain.vectorstores.faiss import FAISS
18
 
 
 
19
  pickle_file = "open_ai.pkl"
20
  index_file = "open_ai.index"
21
 
22
- gpt_3_5 = OpenAI(model_name='gpt-4',temperature=0)
23
 
24
- embeddings = OpenAIEmbeddings()
 
 
 
 
25
 
26
  chat_history = []
27
 
@@ -29,54 +33,17 @@ memory = ConversationBufferWindowMemory(memory_key="chat_history")
29
 
30
  gpt_3_5_index = None
31
 
32
- class CustomOutputParser(AgentOutputParser):
33
-
34
- def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
35
- # Check if agent replied without using tools
36
- if "AI:" in llm_output:
37
- return AgentFinish(return_values={"output": llm_output.split("AI:")[-1].strip()},
38
- log=llm_output)
39
- # Check if agent should finish
40
- if "Final Answer:" in llm_output:
41
- return AgentFinish(
42
- # Return values is generally always a dictionary with a single `output` key
43
- # It is not recommended to try anything else at the moment :)
44
- return_values={"output": llm_output.split("Final Answer:")[-1].strip()},
45
- log=llm_output,
46
- )
47
- # Parse out the action and action input
48
- regex = r"Action: (.*?)[\n]*Action Input:[\s]*(.*)"
49
- match = re.search(regex, llm_output, re.DOTALL)
50
- if not match:
51
- raise ValueError(f"Could not parse LLM output: `{llm_output}`")
52
- action = match.group(1).strip()
53
- action_input = match.group(2)
54
- # Return the action and action input
55
- return AgentAction(tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output)
56
-
57
- # Set up a prompt template
58
- class CustomPromptTemplate(BaseChatPromptTemplate):
59
- # The template to use
60
- template: str
61
- # The list of tools available
62
- tools: List[Tool]
63
-
64
- def format_messages(self, **kwargs) -> str:
65
- # Get the intermediate steps (AgentAction, Observation tuples)
66
- # Format them in a particular way
67
- intermediate_steps = kwargs.pop("intermediate_steps")
68
- thoughts = ""
69
- for action, observation in intermediate_steps:
70
- thoughts += action.log
71
- thoughts += f"\nObservation: {observation}\nThought: "
72
- # Set the agent_scratchpad variable to that value
73
- kwargs["agent_scratchpad"] = thoughts
74
- # Create a tools variable from the list of tools provided
75
- kwargs["tools"] = "\n".join([f"{tool.name}: {tool.description}" for tool in self.tools])
76
- # Create a list of tool names for the tools provided
77
- kwargs["tool_names"] = ", ".join([tool.name for tool in self.tools])
78
- formatted = self.template.format(**kwargs)
79
- return [HumanMessage(content=formatted)]
80
 
81
  def get_search_index():
82
  global gpt_3_5_index
@@ -88,6 +55,7 @@ def get_search_index():
88
  search_index = create_index()
89
 
90
  gpt_3_5_index = search_index
 
91
 
92
 
93
  def create_index():
@@ -140,8 +108,12 @@ def create_chunk_documents():
140
 
141
  def get_qa_chain(gpt_3_5_index):
142
  global gpt_3_5
143
- return ConversationalRetrievalChain.from_llm(gpt_3_5, chain_type="stuff", get_chat_history=get_chat_history,
144
- retriever=gpt_3_5_index.as_retriever(), return_source_documents=True, verbose=True)
 
 
 
 
145
 
146
  def get_chat_history(inputs) -> str:
147
  res = []
@@ -153,117 +125,16 @@ def get_chat_history(inputs) -> str:
153
  def generate_answer(question) -> str:
154
  global chat_history, gpt_3_5_index
155
  gpt_3_5_chain = get_qa_chain(gpt_3_5_index)
 
156
  result = gpt_3_5_chain(
157
  {"question": question, "chat_history": chat_history, "vectordbkwargs": {"search_distance": 0.6}})
158
  chat_history = [(question, result["answer"])]
159
  sources = []
 
160
 
161
  for document in result['source_documents']:
162
  source = document.metadata['source']
163
  sources.append(source.split('/')[-1].split('.')[0])
164
 
165
  source = ',\n'.join(set(sources))
166
- return result['answer'] + '\nSOURCES: ' + source
167
-
168
-
169
- def get_agent_chain(prompt, tools):
170
- global gpt_3_5
171
- llm_chain = LLMChain(llm=gpt_3_5, prompt=prompt)
172
- agent = ConversationalAgent(llm_chain=llm_chain, tools=tools, verbose=True)
173
- agent_chain = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True, memory=memory,
174
- intermediate_steps=True)
175
- return agent_chain
176
-
177
-
178
- def get_prompt_and_tools():
179
- tools = get_tools()
180
-
181
- prefix = """Have a conversation with a human, answering the following questions as best you can. Always try to use Vectorstore first. Your name is Coursera Bot because your knowledge base is Coursera course. You have access to the following tools:"""
182
- suffix = """Begin! If you used vectorstore tool, ALWAYS return a "SOURCES" part in your answer"
183
-
184
- {chat_history}
185
- Question: {input}
186
- {agent_scratchpad}
187
- sources:"""
188
- prompt = ConversationalAgent.create_prompt(
189
- tools,
190
- prefix=prefix,
191
- suffix=suffix,
192
- input_variables=["input", "chat_history", "agent_scratchpad"]
193
- )
194
- return prompt, tools
195
-
196
-
197
- def get_tools():
198
- tools = [
199
- Tool(
200
- name="Vectorstore",
201
- func=generate_answer,
202
- description="useful for when you need to answer questions about the coursera course on 3D Printing.",
203
- return_direct=True
204
- )]
205
- return tools
206
-
207
- def get_custom_agent(prompt, tools):
208
-
209
- llm_chain = LLMChain(llm=gpt_3_5, prompt=prompt)
210
-
211
- output_parser = CustomOutputParser()
212
- tool_names = [tool.name for tool in tools]
213
- agent = LLMSingleActionAgent(
214
- llm_chain=llm_chain,
215
- output_parser=output_parser,
216
- stop=["\nObservation:"],
217
- allowed_tools=tool_names
218
- )
219
- agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True, memory=memory,
220
- intermediate_steps=True)
221
- return agent_executor
222
-
223
- def get_prompt_and_tools_for_custom_agent():
224
- template = """
225
- Have a conversation with a human, answering the following questions as best you can.
226
- ALWAYS try to use Vectorstore first.
227
- You are a teaching assistant for a Coursera Course: The 3D Printing Evolution and can answer any question about that using vectorstore . You have access to the following tools:
228
-
229
- {tools}
230
-
231
- ALWAYS use one of the 2 formats listed below to respond.
232
-
233
- To answer for the new input, use the following format:
234
-
235
- New Input: the input question you must answer
236
- Thought: Do I need to use a tool? Yes
237
- Action: the action to take, should be one of [{tool_names}]
238
- Action Input: the input to the action
239
- Observation: the result of the action
240
- ... (this Thought/Action/Action Input/Observation can repeat N times)
241
- Thought: I now know the final answer
242
- Final Answer: the final answer to the original input question. SOURCES: the sources referred to find the final answer
243
-
244
-
245
- When you have a response to say to the Human and DO NOT need to use a tool:
246
- 1. DO NOT return "SOURCES" if you did not use any tool.
247
- 2. You MUST use this format:
248
- ```
249
- Thought: Do I need to use a tool? No
250
- AI: [your response here]
251
- ```
252
-
253
- Begin! Remember to speak as a personal assistant when giving your final answer.
254
- ALWAYS return a "SOURCES" part in your answer, if you used any tool.
255
-
256
- Previous conversation history:
257
- {chat_history}
258
- New input: {input}
259
- {agent_scratchpad}
260
- SOURCES:"""
261
- tools = get_tools()
262
- prompt = CustomPromptTemplate(
263
- template=template,
264
- tools=tools,
265
- # This omits the `agent_scratchpad`, `tools`, and `tool_names` variables because those are generated dynamically
266
- # This includes the `intermediate_steps` variable because that is needed
267
- input_variables=["input", "intermediate_steps", "chat_history"]
268
- )
269
- return prompt, tools
 
1
  import os
2
  import pickle
 
 
3
 
4
  import faiss
 
 
 
5
  from langchain.chains import ConversationalRetrievalChain
6
+ from langchain.chat_models import ChatOpenAI
7
  from langchain.document_loaders import DirectoryLoader, TextLoader, UnstructuredHTMLLoader
8
  from langchain.embeddings import OpenAIEmbeddings
9
  from langchain.memory import ConversationBufferWindowMemory
10
+ from langchain.prompts.chat import (
11
+ ChatPromptTemplate,
12
+ HumanMessagePromptTemplate,
13
+ SystemMessagePromptTemplate,
14
+ )
15
  from langchain.text_splitter import CharacterTextSplitter
16
  from langchain.vectorstores.faiss import FAISS
17
 
18
+ os.environ['OPENAI_API_KEY'] = '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'
19
+
20
  pickle_file = "open_ai.pkl"
21
  index_file = "open_ai.index"
22
 
 
23
 
24
+
25
+ gpt_3_5 = ChatOpenAI(model_name='gpt-4',temperature=0.1)
26
+
27
+ embeddings = OpenAIEmbeddings(model='text-embedding-ada-002')
28
+
29
 
30
  chat_history = []
31
 
 
33
 
34
  gpt_3_5_index = None
35
 
36
+ system_template = """You are Coursera QA Bot. Have a conversation with a human, answering the following questions as best you can.
37
+ You are a teaching assistant for a Coursera Course: The 3D Printing Evolution and can answer any question about that using vectorstore.
38
+ Use the following pieces of context to answer the users question.
39
+ ----------------
40
+ {context}"""
41
+
42
+ messages = [
43
+ SystemMessagePromptTemplate.from_template(system_template),
44
+ HumanMessagePromptTemplate.from_template("{question}"),
45
+ ]
46
+ CHAT_PROMPT = ChatPromptTemplate.from_messages(messages)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
  def get_search_index():
49
  global gpt_3_5_index
 
55
  search_index = create_index()
56
 
57
  gpt_3_5_index = search_index
58
+ return search_index
59
 
60
 
61
  def create_index():
 
108
 
109
  def get_qa_chain(gpt_3_5_index):
110
  global gpt_3_5
111
+ # embeddings_filter = EmbeddingsFilter(embeddings=embeddings, similarity_threshold=0.76)
112
+ # compression_retriever = ContextualCompressionRetriever(base_compressor=embeddings_filter, base_retriever=gpt_3_5_index.as_retriever())
113
+ chain = ConversationalRetrievalChain.from_llm(gpt_3_5, gpt_3_5_index.as_retriever(), return_source_documents=True,
114
+ verbose=True, get_chat_history=get_chat_history,
115
+ combine_docs_chain_kwargs={"prompt": CHAT_PROMPT})
116
+ return chain
117
 
118
  def get_chat_history(inputs) -> str:
119
  res = []
 
125
  def generate_answer(question) -> str:
126
  global chat_history, gpt_3_5_index
127
  gpt_3_5_chain = get_qa_chain(gpt_3_5_index)
128
+
129
  result = gpt_3_5_chain(
130
  {"question": question, "chat_history": chat_history, "vectordbkwargs": {"search_distance": 0.6}})
131
  chat_history = [(question, result["answer"])]
132
  sources = []
133
+ print(result['answer'])
134
 
135
  for document in result['source_documents']:
136
  source = document.metadata['source']
137
  sources.append(source.split('/')[-1].split('.')[0])
138
 
139
  source = ',\n'.join(set(sources))
140
+ return result['answer'] + '\nSOURCES: ' + source
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
utils_old.py ADDED
@@ -0,0 +1,271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pickle
3
+ import re
4
+ from typing import List, Union
5
+
6
+ import faiss
7
+ from langchain import OpenAI, LLMChain
8
+ from langchain.agents import ConversationalAgent
9
+ from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser
10
+ from langchain.chains import ConversationalRetrievalChain
11
+ from langchain.document_loaders import DirectoryLoader, TextLoader, UnstructuredHTMLLoader
12
+ from langchain.embeddings import OpenAIEmbeddings
13
+ from langchain.memory import ConversationBufferWindowMemory
14
+ from langchain.prompts import BaseChatPromptTemplate
15
+ from langchain.schema import AgentAction, AgentFinish, HumanMessage
16
+ from langchain.text_splitter import CharacterTextSplitter
17
+ from langchain.vectorstores.faiss import FAISS
18
+
19
+ os.environ['OPENAI_API_KEY'] = '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'
20
+
21
+ pickle_file = "open_ai.pkl"
22
+ index_file = "open_ai.index"
23
+
24
+ gpt_3_5 = OpenAI(model_name='gpt-4',temperature=0)
25
+
26
+ embeddings = OpenAIEmbeddings()
27
+
28
+ chat_history = []
29
+
30
+ memory = ConversationBufferWindowMemory(memory_key="chat_history")
31
+
32
+ gpt_3_5_index = None
33
+
34
+ class CustomOutputParser(AgentOutputParser):
35
+
36
+ def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
37
+ # Check if agent replied without using tools
38
+ if "AI:" in llm_output:
39
+ return AgentFinish(return_values={"output": llm_output.split("AI:")[-1].strip()},
40
+ log=llm_output)
41
+ # Check if agent should finish
42
+ if "Final Answer:" in llm_output:
43
+ return AgentFinish(
44
+ # Return values is generally always a dictionary with a single `output` key
45
+ # It is not recommended to try anything else at the moment :)
46
+ return_values={"output": llm_output.split("Final Answer:")[-1].strip()},
47
+ log=llm_output,
48
+ )
49
+ # Parse out the action and action input
50
+ regex = r"Action: (.*?)[\n]*Action Input:[\s]*(.*)"
51
+ match = re.search(regex, llm_output, re.DOTALL)
52
+ if not match:
53
+ raise ValueError(f"Could not parse LLM output: `{llm_output}`")
54
+ action = match.group(1).strip()
55
+ action_input = match.group(2)
56
+ # Return the action and action input
57
+ return AgentAction(tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output)
58
+
59
+ # Set up a prompt template
60
+ class CustomPromptTemplate(BaseChatPromptTemplate):
61
+ # The template to use
62
+ template: str
63
+ # The list of tools available
64
+ tools: List[Tool]
65
+
66
+ def format_messages(self, **kwargs) -> str:
67
+ # Get the intermediate steps (AgentAction, Observation tuples)
68
+ # Format them in a particular way
69
+ intermediate_steps = kwargs.pop("intermediate_steps")
70
+ thoughts = ""
71
+ for action, observation in intermediate_steps:
72
+ thoughts += action.log
73
+ thoughts += f"\nObservation: {observation}\nThought: "
74
+ # Set the agent_scratchpad variable to that value
75
+ kwargs["agent_scratchpad"] = thoughts
76
+ # Create a tools variable from the list of tools provided
77
+ kwargs["tools"] = "\n".join([f"{tool.name}: {tool.description}" for tool in self.tools])
78
+ # Create a list of tool names for the tools provided
79
+ kwargs["tool_names"] = ", ".join([tool.name for tool in self.tools])
80
+ formatted = self.template.format(**kwargs)
81
+ return [HumanMessage(content=formatted)]
82
+
83
+ def get_search_index():
84
+ global gpt_3_5_index
85
+ if os.path.isfile(pickle_file) and os.path.isfile(index_file) and os.path.getsize(pickle_file) > 0:
86
+ # Load index from pickle file
87
+ with open(pickle_file, "rb") as f:
88
+ search_index = pickle.load(f)
89
+ else:
90
+ search_index = create_index()
91
+
92
+ gpt_3_5_index = search_index
93
+
94
+
95
+ def create_index():
96
+ source_chunks = create_chunk_documents()
97
+ search_index = search_index_from_docs(source_chunks)
98
+ faiss.write_index(search_index.index, index_file)
99
+ # Save index to pickle file
100
+ with open(pickle_file, "wb") as f:
101
+ pickle.dump(search_index, f)
102
+ return search_index
103
+
104
+
105
+ def search_index_from_docs(source_chunks):
106
+ # print("source chunks: " + str(len(source_chunks)))
107
+ # print("embeddings: " + str(embeddings))
108
+ search_index = FAISS.from_documents(source_chunks, embeddings)
109
+ return search_index
110
+
111
+
112
+ def get_html_files():
113
+ loader = DirectoryLoader('docs', glob="**/*.html", loader_cls=UnstructuredHTMLLoader, recursive=True)
114
+ document_list = loader.load()
115
+ return document_list
116
+
117
+
118
+ def fetch_data_for_embeddings():
119
+ document_list = get_text_files()
120
+ document_list.extend(get_html_files())
121
+ print("document list" + str(len(document_list)))
122
+ return document_list
123
+
124
+
125
+ def get_text_files():
126
+ loader = DirectoryLoader('docs', glob="**/*.txt", loader_cls=TextLoader, recursive=True)
127
+ document_list = loader.load()
128
+ return document_list
129
+
130
+
131
+ def create_chunk_documents():
132
+ sources = fetch_data_for_embeddings()
133
+
134
+ splitter = CharacterTextSplitter(separator=" ", chunk_size=800, chunk_overlap=0)
135
+
136
+ source_chunks = splitter.split_documents(sources)
137
+
138
+ print("sources" + str(len(source_chunks)))
139
+
140
+ return source_chunks
141
+
142
+
143
+ def get_qa_chain(gpt_3_5_index):
144
+ global gpt_3_5
145
+ return ConversationalRetrievalChain.from_llm(gpt_3_5, chain_type="stuff", get_chat_history=get_chat_history,
146
+ retriever=gpt_3_5_index.as_retriever(), return_source_documents=True, verbose=True)
147
+
148
+ def get_chat_history(inputs) -> str:
149
+ res = []
150
+ for human, ai in inputs:
151
+ res.append(f"Human:{human}\nAI:{ai}")
152
+ return "\n".join(res)
153
+
154
+
155
+ def generate_answer(question) -> str:
156
+ global chat_history, gpt_3_5_index
157
+ gpt_3_5_chain = get_qa_chain(gpt_3_5_index)
158
+ result = gpt_3_5_chain(
159
+ {"question": question, "chat_history": chat_history, "vectordbkwargs": {"search_distance": 0.6}})
160
+ chat_history = [(question, result["answer"])]
161
+ sources = []
162
+
163
+ for document in result['source_documents']:
164
+ source = document.metadata['source']
165
+ sources.append(source.split('/')[-1].split('.')[0])
166
+
167
+ source = ',\n'.join(set(sources))
168
+ return result['answer'] + '\nSOURCES: ' + source
169
+
170
+
171
+ def get_agent_chain(prompt, tools):
172
+ global gpt_3_5
173
+ llm_chain = LLMChain(llm=gpt_3_5, prompt=prompt)
174
+ agent = ConversationalAgent(llm_chain=llm_chain, tools=tools, verbose=True)
175
+ agent_chain = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True, memory=memory,
176
+ intermediate_steps=True)
177
+ return agent_chain
178
+
179
+
180
+ def get_prompt_and_tools():
181
+ tools = get_tools()
182
+
183
+ prefix = """Have a conversation with a human, answering the following questions as best you can. Always try to use Vectorstore first. Your name is Coursera Bot because your knowledge base is Coursera course. You have access to the following tools:"""
184
+ suffix = """Begin! If you used vectorstore tool, ALWAYS return a "SOURCES" part in your answer"
185
+
186
+ {chat_history}
187
+ Question: {input}
188
+ {agent_scratchpad}
189
+ sources:"""
190
+ prompt = ConversationalAgent.create_prompt(
191
+ tools,
192
+ prefix=prefix,
193
+ suffix=suffix,
194
+ input_variables=["input", "chat_history", "agent_scratchpad"]
195
+ )
196
+ return prompt, tools
197
+
198
+
199
+ def get_tools():
200
+ tools = [
201
+ Tool(
202
+ name="Vectorstore",
203
+ func=generate_answer,
204
+ description="useful for when you need to answer questions about the coursera course on 3D Printing.",
205
+ return_direct=True
206
+ )]
207
+ return tools
208
+
209
+ def get_custom_agent(prompt, tools):
210
+
211
+ llm_chain = LLMChain(llm=gpt_3_5, prompt=prompt)
212
+
213
+ output_parser = CustomOutputParser()
214
+ tool_names = [tool.name for tool in tools]
215
+ agent = LLMSingleActionAgent(
216
+ llm_chain=llm_chain,
217
+ output_parser=output_parser,
218
+ stop=["\nObservation:"],
219
+ allowed_tools=tool_names
220
+ )
221
+ agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True, memory=memory,
222
+ intermediate_steps=True)
223
+ return agent_executor
224
+
225
+ def get_prompt_and_tools_for_custom_agent():
226
+ template = """
227
+ Have a conversation with a human, answering the following questions as best you can.
228
+ ALWAYS try to use Vectorstore first.
229
+ You are a teaching assistant for a Coursera Course: The 3D Printing Evolution and can answer any question about that using vectorstore . You have access to the following tools:
230
+
231
+ {tools}
232
+
233
+ ALWAYS use one of the 2 formats listed below to respond.
234
+
235
+ To answer for the new input, use the following format:
236
+
237
+ New Input: the input question you must answer
238
+ Thought: Do I need to use a tool? Yes
239
+ Action: the action to take, should be one of [{tool_names}]
240
+ Action Input: the input to the action
241
+ Observation: the result of the action
242
+ ... (this Thought/Action/Action Input/Observation can repeat N times)
243
+ Thought: I now know the final answer
244
+ Final Answer: the final answer to the original input question. SOURCES: the sources referred to find the final answer
245
+
246
+
247
+ When you have a response to say to the Human and DO NOT need to use a tool:
248
+ 1. DO NOT return "SOURCES" if you did not use any tool.
249
+ 2. You MUST use this format:
250
+ ```
251
+ Thought: Do I need to use a tool? No
252
+ AI: [your response here]
253
+ ```
254
+
255
+ Begin! Remember to speak as a personal assistant when giving your final answer.
256
+ ALWAYS return a "SOURCES" part in your answer, if you used any tool.
257
+
258
+ Previous conversation history:
259
+ {chat_history}
260
+ New input: {input}
261
+ {agent_scratchpad}
262
+ SOURCES:"""
263
+ tools = get_tools()
264
+ prompt = CustomPromptTemplate(
265
+ template=template,
266
+ tools=tools,
267
+ # This omits the `agent_scratchpad`, `tools`, and `tool_names` variables because those are generated dynamically
268
+ # This includes the `intermediate_steps` variable because that is needed
269
+ input_variables=["input", "intermediate_steps", "chat_history"]
270
+ )
271
+ return prompt, tools