Files changed (9) hide show
  1. app.py +3 -20
  2. main.py +14 -19
  3. open_ai.index +2 -2
  4. open_ai.pkl +2 -2
  5. requirements.txt +9 -10
  6. static/chatbot.js +9 -97
  7. static/style.css +9 -153
  8. templates/index.html +0 -7
  9. utils.py +20 -219
app.py CHANGED
@@ -1,21 +1,13 @@
1
  from flask import Flask, render_template
2
- from flask_executor import Executor
3
  from flask_socketio import SocketIO, emit
4
  from flask_cors import cross_origin, CORS
5
  from main import run
6
- from gevent import monkey
7
 
8
- monkey.patch_all(ssl=False)
9
  app = Flask(__name__)
10
  app.config['SECRET_KEY'] = 'secret!'
11
- socketio = SocketIO(app, cors_allowed_origins="*", async_mode='gevent', logger=True)
12
  cors = CORS(app)
13
 
14
- executor = Executor(app)
15
-
16
- executor.init_app(app)
17
- app.config['EXECUTOR_MAX_WORKERS'] = 10
18
-
19
  @app.route('/')
20
  def index():
21
  return render_template('index.html')
@@ -25,18 +17,9 @@ def index():
25
  def handle_message(data):
26
  question = data['question']
27
  print("question: " + question)
 
 
28
 
29
- if executor.futures:
30
- emit('response', {'response': 'Server is busy, please try again later'})
31
- return
32
-
33
- try:
34
- future = executor.submit(run, question)
35
- response = future.result()
36
- emit('response', {'response': response})
37
- except Exception as e:
38
- traceback.print_exc()
39
- emit('response', {'response': 'Server is busy. Please try again later.'})
40
 
41
  if __name__ == '__main__':
42
  socketio.run(app, host="0.0.0.0", port=7860)
 
1
  from flask import Flask, render_template
 
2
  from flask_socketio import SocketIO, emit
3
  from flask_cors import cross_origin, CORS
4
  from main import run
 
5
 
 
6
  app = Flask(__name__)
7
  app.config['SECRET_KEY'] = 'secret!'
8
+ socketio = SocketIO(app, cors_allowed_origins="*", async_mode='gevent')
9
  cors = CORS(app)
10
 
 
 
 
 
 
11
  @app.route('/')
12
  def index():
13
  return render_template('index.html')
 
17
  def handle_message(data):
18
  question = data['question']
19
  print("question: " + question)
20
+ response = run(question)
21
+ emit('response', {'response': response})
22
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  if __name__ == '__main__':
25
  socketio.run(app, host="0.0.0.0", port=7860)
main.py CHANGED
@@ -1,27 +1,22 @@
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
- def run(question):
6
-
7
- index = get_search_index()
8
 
9
- # prompt, tools = get_prompt_and_tools()
 
10
 
11
- # agent_chain = get_agent_chain(prompt, tools)
12
 
13
- prompt, tools = get_prompt_and_tools_for_custom_agent()
14
 
15
- agent_chain = get_custom_agent(prompt, tools)
16
 
17
- result = None
18
 
19
- try:
20
- result = agent_chain.run(question)
21
- print(result)
22
- except ValueError as ve:
23
- if "Could not parse LLM output:" in ve.args[0] and question.lower().startswith(tuple(question_starters)) and not question.lower().endswith('?'):
24
- question = question + '?'
25
- result = agent_chain.run(question)
26
 
27
- return result
 
 
1
+ from langchain.chains.qa_with_sources.loading import load_qa_with_sources_chain
2
+ from langchain.embeddings.openai import OpenAIEmbeddings
3
+ from langchain.llms import OpenAI
4
 
5
+ from utils import generate_answer
6
+ from utils import get_search_index
 
7
 
8
+ open_ai_pkl = "open_ai.pkl"
9
+ open_ai_index = "open_ai.index"
10
 
11
+ gpt_3_5 = OpenAI(model_name='gpt-3.5-turbo',temperature=0)
12
 
13
+ open_ai_embeddings = OpenAIEmbeddings()
14
 
15
+ def run(question):
16
 
17
+ gpt_3_5_index = get_search_index(open_ai_pkl, open_ai_index, open_ai_embeddings)
18
 
19
+ gpt_3_5_chain = load_qa_with_sources_chain(gpt_3_5, chain_type="stuff", verbose=True)
 
 
 
 
 
 
20
 
21
+ answer = generate_answer(gpt_3_5_chain, gpt_3_5_index, question)
22
+ return answer
open_ai.index CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:f5a87eb7dbbfd3245fc8025fb2467723bdcba8cdf308127050de9f8bbdeb21bc
3
- size 2838573
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1d25013b3bf7b7195d01ec1cc9ac1527638d8db68d94556b3dcc69b7dd8ff704
3
+ size 3016749
open_ai.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:7c399ec43dab5c11fabcc598d507b88db77a59b019c1b2533f2792199c6a1fcc
3
- size 3171039
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9c903018b7b3ad6f89b802f0e36fc92c88fb793c4f6e2499687b8823050a4df0
3
+ size 3373815
requirements.txt CHANGED
@@ -1,11 +1,10 @@
1
  faiss-cpu==1.7.3
2
- langchain==0.0.131
3
- beautifulsoup4==4.12.0
4
- PyPDF2==3.0.1
5
- openai==0.27.4
6
- flask==2.2.3
7
- flask-socketio==5.3.3
8
- flask-cors==3.0.10
9
- flask-executor==1.0.0
10
- gevent==22.10.2
11
- gevent-websocket==0.10.1
 
1
  faiss-cpu==1.7.3
2
+ langchain==0.0.117
3
+ beautifulsoup4
4
+ PyPDF2
5
+ openai
6
+ flask
7
+ flask-socketio
8
+ flask-cors
9
+ gevent
10
+ gevent-websocket
 
static/chatbot.js CHANGED
@@ -1,39 +1,15 @@
1
  $(document).ready(function() {
2
  // Initialize variables
3
- var $chatContainer = $('.chat-container');
4
- var $chatHeader = $('.chat-header');
5
- var $chatBody = $('.chat-body');
6
- var $chatInput = $('.chat-input');
7
  var $input = $('.chat-input input');
8
  var $submit = $('.chat_submit');
9
  var session_id = '';
10
- $chatBody.children().each(function() {
11
  $(this).addClass('chat-message');
12
  });
13
- const buttonLabels = ["What is Makerlab?", "What is 3D printing?",
14
- "Who are the founders of Makerlab?", "What are the 3D printing prices at Makerlab?",
15
- "How can I host a birthday at Makerlab?", "Can I book an appointment at Makerlab?",
16
- "Tell me about softwares used to create 3D printing designs", "Hi, I am bob. Tell me when Makerlab was founded.",
17
- "Can I get my custom designs 3D printed at Makerlab?", "Can I host a private event at Makerlab?",
18
- "Does Makerlab host any workshop?", "When is Makerlab open?", "How can I contact the Makerlab Team?"];
19
-
20
 
21
  // Initialize SocketIO connection
22
  var socket = io.connect('https://' + document.domain + ':' + location.port);
23
- const container = document.getElementById("button-container");
24
-
25
-
26
- for (let i = 0; i < buttonLabels.length; i++) {
27
-
28
- const button = document.createElement("button");
29
- button.innerHTML = buttonLabels[i];
30
- button.setAttribute("class", "queries");
31
- button.setAttribute("id", `button-${i}`);
32
- button.style.margin = "5px";
33
- container.appendChild(button);
34
- }
35
- scrollButtons();
36
-
37
 
38
  // Function to send message to Flask-SocketIO app
39
  function sendMessage(message) {
@@ -42,14 +18,9 @@ $(document).ready(function() {
42
  }
43
 
44
  // Function to display message
45
- function displayMessage(message, isUser, hasHtml) {
46
  var $message = $('<div>').addClass('chat-message round');
47
- if (hasHtml) {
48
- $messageText = $('<p>').html(message);
49
- } else {
50
- $messageText = $('<p>').html(message.replace(/(https?:\/\/[^\s,]+)/g, '<a href="$1" target="_blank">$1</a>').replace(/(SOURCES:)/, '<br>$1'));
51
- }
52
- // var $messageText = $('<p>').html(message.replace(/(https?:\/\/[^\s,]+)/g, '<a href="$1">$1</a>'));
53
 
54
  $message.append($messageText);
55
  if (isUser) {
@@ -57,10 +28,10 @@ $(document).ready(function() {
57
  } else {
58
  $message.addClass('bot')
59
  }
60
- if ($chatBody) {
61
- $chatBody.append($message);
62
- if ($chatBody[0]) {
63
- $chatBody.animate({scrollTop: $chatBody[0].scrollHeight}, 300);
64
  }
65
  } else {
66
  $('.chat-container').append($message);
@@ -97,64 +68,5 @@ $(document).ready(function() {
97
  });
98
 
99
  // Initial message
100
- displayMessage('Learn about <a href="https://makerlab.illinois.edu/" target="_blank">Makerlab</a>', false, true);
101
- displayMessage('This bot is powered by Gpt 3.5 and thus may get things wrong. You can click on any of the questions on the left and they will get copied to this window. You can also type in a question here.  If you find the bot useful or have feedback on improving it, drop us a line at <a href="https://makerlab.illinois.edu/contact" target="_blank">Makerlab - Contact</a>', false, true);
102
-
103
- // Function to minimize the widget
104
- function minimizeWidget() {
105
- $chatContainer.addClass('minimized');
106
- $chatHeader.hide();
107
- $chatBody.hide()
108
- $chatInput.hide();
109
- $chatContainer.append('<div class="chat-bot-icon"><i class="fa fa-android"></i></div>');
110
- }
111
-
112
- // Function to maximize the widget
113
- function maximizeWidget() {
114
- $chatContainer.removeClass('minimized');
115
- $chatBody.show()
116
- $chatHeader.show();
117
- $chatInput.show();
118
- $('.chat-bot-icon').remove();
119
- }
120
-
121
- // Minimize the widget on click of close button
122
- $chatHeader.find('.chat-close').click(function() {
123
- minimizeWidget();
124
- });
125
-
126
- // Maximize the widget on click of chat-bot-icon
127
- $chatContainer.on('click', '.chat-bot-icon', function() {
128
- maximizeWidget();
129
- });
130
-
131
- // Add event listener to each button
132
- $('.queries').click(function() {
133
- // Set the value of the input field to the text content of the clicked button
134
- $('input[type="text"]').val($(this).text());
135
- });
136
-
137
- function scrollButtons() {
138
- var container = document.getElementById("button-container");
139
- var buttons = container.querySelectorAll(".queries");
140
- var current = 0;
141
-
142
- var scrollInterval = setInterval(function() {
143
- buttons[current].scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
144
- current = (current + 1) % buttons.length;
145
- }, 1000);
146
-
147
- container.addEventListener("mouseenter", function() {
148
- clearInterval(scrollInterval);
149
- });
150
-
151
- container.addEventListener("mouseleave", function() {
152
- scrollInterval = setInterval(function() {
153
- buttons[current].scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
154
- current = (current + 1) % buttons.length;
155
- }, 1000);
156
- });
157
- }
158
-
159
-
160
  });
 
1
  $(document).ready(function() {
2
  // Initialize variables
3
+ var $messages = $('.chat-messages');
 
 
 
4
  var $input = $('.chat-input input');
5
  var $submit = $('.chat_submit');
6
  var session_id = '';
7
+ $messages.children().each(function() {
8
  $(this).addClass('chat-message');
9
  });
 
 
 
 
 
 
 
10
 
11
  // Initialize SocketIO connection
12
  var socket = io.connect('https://' + document.domain + ':' + location.port);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  // Function to send message to Flask-SocketIO app
15
  function sendMessage(message) {
 
18
  }
19
 
20
  // Function to display message
21
+ function displayMessage(message, isUser) {
22
  var $message = $('<div>').addClass('chat-message round');
23
+ var $messageText = $('<p>').html(message.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1">$1</a>'));
 
 
 
 
 
24
 
25
  $message.append($messageText);
26
  if (isUser) {
 
28
  } else {
29
  $message.addClass('bot')
30
  }
31
+ if ($messages) {
32
+ $messages.append($message);
33
+ if ($messages[0]) {
34
+ $messages.animate({scrollTop: $messages[0].scrollHeight}, 300);
35
  }
36
  } else {
37
  $('.chat-container').append($message);
 
68
  });
69
 
70
  // Initial message
71
+ displayMessage('Ask me anything');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  });
static/style.css CHANGED
@@ -7,7 +7,7 @@
7
  border-radius: 10px;
8
  box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.2);
9
  max-width: 400px;
10
- min-width: 400px;
11
  }
12
 
13
  .round {
@@ -22,7 +22,7 @@
22
  align-items: center;
23
  justify-content: space-between;
24
  padding: 10px;
25
- background-color: darkblue;
26
  color: #fff;
27
  border-top-left-radius: 10px;
28
  border-top-right-radius: 10px;
@@ -37,7 +37,7 @@
37
  }
38
 
39
  .chat-body {
40
- height: 400px;
41
  overflow-y: scroll;
42
  padding: 10px;
43
  word-wrap: break-word;
@@ -57,7 +57,6 @@
57
  position: relative;
58
  word-wrap: break-word;
59
  border-radius: 10px;
60
- color: #fff;
61
  }
62
 
63
  .chat-message.user {
@@ -66,11 +65,12 @@
66
  justify-content: flex-end;
67
  text-align: right;
68
  align-items: center;
69
- background-color: rgba(0, 0, 139, 0.75);
70
  border-top-right-radius: 0px;
71
  border-bottom-right-radius: 0px;
72
  border-bottom-left-radius: 10px;
73
  word-wrap: break-word;
 
74
  }
75
 
76
 
@@ -80,7 +80,7 @@
80
  justify-content: flex-start;
81
  text-align: left;
82
  align-items: center;
83
- background-color: rgba(0, 0, 139, 0.75);
84
  border-top-left-radius: 0px;
85
  border-bottom-right-radius: 10px;
86
  border-bottom-left-radius: 0px;
@@ -107,7 +107,7 @@
107
  height: 0;
108
  border-top: 15px solid transparent;
109
  border-bottom: 15px solid transparent;
110
- border-left: 16px solid #00008BBF;
111
  border-top-right-radius: 10px;
112
  }
113
 
@@ -120,7 +120,7 @@
120
  height: 0;
121
  border-top: 15px solid transparent;
122
  border-bottom: 15px solid transparent;
123
- border-right: 15px solid #00008BBF;
124
  border-top-left-radius: 10px;
125
  }
126
 
@@ -141,7 +141,7 @@
141
  }
142
 
143
  .chat-input button {
144
- background-color: #00008BBF;
145
  color: #fff;
146
  border: none;
147
  border-radius: 5px;
@@ -150,147 +150,3 @@
150
  cursor: pointer;
151
  box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
152
  }
153
-
154
- /* CSS for chat-container when minimized */
155
- .chat-container.minimized {
156
- min-width: 70px;
157
- height: 70px;
158
- border-radius: 50%;
159
- position: fixed;
160
- bottom: 10px;
161
- right: 10px;
162
- z-index: 9999;
163
- background-color: #fff;
164
- box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.3);
165
- cursor: pointer;
166
- }
167
-
168
- /* CSS for chat-bot-icon */
169
- .chat-bot-icon {
170
- font-size: 30px;
171
- color: #00008BBF;
172
- position: absolute;
173
- top: 50%;
174
- left: 50%;
175
- transform: translate(-50%, -50%);
176
- }
177
-
178
- /* CSS for chat-header when not minimized */
179
- .chat-header {
180
- display: flex;
181
- justify-content: space-between;
182
- align-items: center;
183
- background-color: #6c7ae0;
184
- color: #fff;
185
- padding: 10px;
186
- border-top-left-radius: 5px;
187
- border-top-right-radius: 5px;
188
- }
189
-
190
- /* CSS for chat-container when not minimized */
191
- .chat-container:not(.minimized) {
192
- border-radius: 5px;
193
- position: fixed;
194
- bottom: 10px;
195
- right: 10px;
196
- z-index: 9999;
197
- background-color: #fff;
198
- box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.3);
199
- }
200
-
201
- /* CSS for chat-bot-icon when chat-container is minimized */
202
- .chat-container.minimized .chat-bot-icon {
203
- display: block;
204
- }
205
-
206
- /* CSS for chat-bot-icon when chat-container is not minimized */
207
- .chat-container:not(.minimized) .chat-bot-icon {
208
- display: none;
209
- }
210
-
211
- .queries {
212
-
213
- padding: 8px 12px;
214
- font-size: 16px;
215
- font-weight: bold;
216
- text-align: center;
217
- text-decoration: none;
218
- border: 0.5px solid #a5a0a0;
219
- border-radius: 20px;
220
- color: #000;
221
- background-color: #343a404a;
222
- cursor: pointer;
223
- margin: 5px;
224
- }
225
-
226
- .queries:hover {
227
- background-color: #343a40ad;
228
- }
229
-
230
- .queries:active {
231
- background-color: #0053a4;
232
- }
233
-
234
- #button-container {
235
- display: flex;
236
- position: relative;
237
- left: 2%;
238
- top: 40%;
239
- flex-direction: column;
240
- justify-content: inherit;
241
- align-items: center;
242
- width: auto;
243
- overflow-y: scroll;
244
- max-height: 350px;
245
- padding-top: 110%;
246
- margin-top: 2%;
247
-
248
- }
249
-
250
- #button-container button {
251
- margin-bottom: 10px;
252
- }
253
-
254
- .query-heading {
255
- display: flex;
256
- position: relative;
257
- width: auto%;
258
- background-color: #fff;
259
- padding: 10px;
260
- z-index: 1;
261
- justify-content: inherit;
262
- width: 100%;
263
- border-bottom: 1px solid #2f4f4f5e;
264
- }
265
-
266
- .sample-query {
267
- display: flex;
268
- position: absolute;
269
- left: 30%;
270
- top: 10%;
271
- flex-direction: column;
272
- justify-content: flex-start;
273
- align-items: center;
274
- width: auto;
275
- padding: 10px;
276
- border: 1px solid #2f4f4f5e;
277
- justify-content: center;
278
- border-radius: 10px;
279
- max-width: 30%;
280
- }
281
-
282
- ::-webkit-scrollbar {
283
- width: 8px;
284
- }
285
-
286
- ::-webkit-scrollbar-track {
287
- background-color: #f4f4f4;
288
- }
289
-
290
- ::-webkit-scrollbar-thumb {
291
- background-color: #a3bfe9a6;
292
- border-radius: 20px;
293
- }
294
-
295
-
296
-
 
7
  border-radius: 10px;
8
  box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.2);
9
  max-width: 400px;
10
+ min-width: 300px;
11
  }
12
 
13
  .round {
 
22
  align-items: center;
23
  justify-content: space-between;
24
  padding: 10px;
25
+ background-color: rgb(113, 239, 234);
26
  color: #fff;
27
  border-top-left-radius: 10px;
28
  border-top-right-radius: 10px;
 
37
  }
38
 
39
  .chat-body {
40
+ height: 300px;
41
  overflow-y: scroll;
42
  padding: 10px;
43
  word-wrap: break-word;
 
57
  position: relative;
58
  word-wrap: break-word;
59
  border-radius: 10px;
 
60
  }
61
 
62
  .chat-message.user {
 
65
  justify-content: flex-end;
66
  text-align: right;
67
  align-items: center;
68
+ background-color: rgba(113, 239, 234, 0.75);
69
  border-top-right-radius: 0px;
70
  border-bottom-right-radius: 0px;
71
  border-bottom-left-radius: 10px;
72
  word-wrap: break-word;
73
+ color: #000;
74
  }
75
 
76
 
 
80
  justify-content: flex-start;
81
  text-align: left;
82
  align-items: center;
83
+ background-color: rgba(113, 239, 234, 0.75);
84
  border-top-left-radius: 0px;
85
  border-bottom-right-radius: 10px;
86
  border-bottom-left-radius: 0px;
 
107
  height: 0;
108
  border-top: 15px solid transparent;
109
  border-bottom: 15px solid transparent;
110
+ border-left: 15px solid #71EFEABF;
111
  border-top-right-radius: 10px;
112
  }
113
 
 
120
  height: 0;
121
  border-top: 15px solid transparent;
122
  border-bottom: 15px solid transparent;
123
+ border-right: 15px solid #71EFEABF;
124
  border-top-left-radius: 10px;
125
  }
126
 
 
141
  }
142
 
143
  .chat-input button {
144
+ background-color: #FFA500;
145
  color: #fff;
146
  border: none;
147
  border-radius: 5px;
 
150
  cursor: pointer;
151
  box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
152
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/index.html CHANGED
@@ -9,18 +9,11 @@
9
  <link rel="stylesheet" href="static/style.css">
10
  </head>
11
  <body>
12
- <div class = "sample-query">
13
- <div class="query-heading"><h4>Sample Queries</h4></div>
14
- <div id="button-container">
15
- </div></div>
16
  <div class="chat-container">
17
  <div class="chat-header">
18
  <h4>Makerlab Q&A Bot</h4>
19
  <i class="fa fa-close chat-close"></i>
20
  </div>
21
- <div class="chat-bot-icon">
22
- <i class="fa fa-android"></i> <!-- Replace with your bot icon -->
23
- </div>
24
  <div class="chat-body chat-messages round"></div>
25
  <div class="chat-input">
26
  <input type="text" placeholder="Type your message">
 
9
  <link rel="stylesheet" href="static/style.css">
10
  </head>
11
  <body>
 
 
 
 
12
  <div class="chat-container">
13
  <div class="chat-header">
14
  <h4>Makerlab Q&A Bot</h4>
15
  <i class="fa fa-close chat-close"></i>
16
  </div>
 
 
 
17
  <div class="chat-body chat-messages round"></div>
18
  <div class="chat-input">
19
  <input type="text" placeholder="Type your message">
utils.py CHANGED
@@ -1,111 +1,36 @@
1
  import os
2
  import pickle
3
- import re
4
  import time
5
- from typing import List, Union
6
  from urllib.parse import urlparse, urljoin
7
 
8
  import faiss
9
  import requests
10
  from PyPDF2 import PdfReader
11
  from bs4 import BeautifulSoup
12
- from langchain import OpenAI, LLMChain
13
- from langchain.agents import ConversationalAgent
14
- from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser
15
- from langchain.prompts import BaseChatPromptTemplate
16
- from langchain.chains import ConversationalRetrievalChain
17
  from langchain.docstore.document import Document
18
- from langchain.embeddings import OpenAIEmbeddings
19
- from langchain.memory import ConversationBufferWindowMemory
20
- from langchain.schema import AgentAction, AgentFinish, HumanMessage
21
  from langchain.text_splitter import CharacterTextSplitter
22
  from langchain.vectorstores.faiss import FAISS
23
 
24
  book_url = 'https://g.co/kgs/2VFC7u'
25
  book_file = "Book.pdf"
26
  url = 'https://makerlab.illinois.edu/'
 
27
 
28
- pickle_file = "open_ai.pkl"
29
- index_file = "open_ai.index"
30
-
31
- gpt_3_5 = OpenAI(model_name='gpt-3.5-turbo',temperature=0)
32
-
33
- embeddings = OpenAIEmbeddings()
34
-
35
- chat_history = []
36
-
37
- memory = ConversationBufferWindowMemory(memory_key="chat_history")
38
-
39
- gpt_3_5_index = None
40
-
41
- class CustomOutputParser(AgentOutputParser):
42
-
43
- def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
44
- # Check if agent replied without using tools
45
- if "AI:" in llm_output:
46
- return AgentFinish(return_values={"output": llm_output.split("AI:")[-1].strip()},
47
- log=llm_output)
48
- # Check if agent should finish
49
- if "Final Answer:" in llm_output:
50
- return AgentFinish(
51
- # Return values is generally always a dictionary with a single `output` key
52
- # It is not recommended to try anything else at the moment :)
53
- return_values={"output": llm_output.split("Final Answer:")[-1].strip()},
54
- log=llm_output,
55
- )
56
- # Parse out the action and action input
57
- regex = r"Action: (.*?)[\n]*Action Input:[\s]*(.*)"
58
- match = re.search(regex, llm_output, re.DOTALL)
59
- if not match:
60
- raise ValueError(f"Could not parse LLM output: `{llm_output}`")
61
- action = match.group(1).strip()
62
- action_input = match.group(2)
63
- # Return the action and action input
64
- return AgentAction(tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output)
65
-
66
- # Set up a prompt template
67
- class CustomPromptTemplate(BaseChatPromptTemplate):
68
- # The template to use
69
- template: str
70
- # The list of tools available
71
- tools: List[Tool]
72
-
73
- def format_messages(self, **kwargs) -> str:
74
- # Get the intermediate steps (AgentAction, Observation tuples)
75
- # Format them in a particular way
76
- intermediate_steps = kwargs.pop("intermediate_steps")
77
- thoughts = ""
78
- for action, observation in intermediate_steps:
79
- thoughts += action.log
80
- thoughts += f"\nObservation: {observation}\nThought: "
81
- # Set the agent_scratchpad variable to that value
82
- kwargs["agent_scratchpad"] = thoughts
83
- # Create a tools variable from the list of tools provided
84
- kwargs["tools"] = "\n".join([f"{tool.name}: {tool.description}" for tool in self.tools])
85
- # Create a list of tool names for the tools provided
86
- kwargs["tool_names"] = ", ".join([tool.name for tool in self.tools])
87
- formatted = self.template.format(**kwargs)
88
- return [HumanMessage(content=formatted)]
89
-
90
- def get_search_index():
91
- global gpt_3_5_index
92
  if os.path.isfile(pickle_file) and os.path.isfile(index_file) and os.path.getsize(pickle_file) > 0:
93
  # Load index from pickle file
94
  with open(pickle_file, "rb") as f:
95
  search_index = pickle.load(f)
96
  else:
97
- search_index = create_index()
98
 
99
- gpt_3_5_index = search_index
100
 
 
 
 
 
 
101
 
102
- def create_index():
103
- source_chunks = create_chunk_documents()
104
- search_index = search_index_from_docs(source_chunks)
105
- faiss.write_index(search_index.index, index_file)
106
- # Save index to pickle file
107
- with open(pickle_file, "wb") as f:
108
- pickle.dump(search_index, f)
109
  return search_index
110
 
111
 
@@ -193,143 +118,19 @@ def get_document_data(book_file, book_url):
193
  # print("document list" + str(len(document_list)))
194
  return document_list
195
 
196
- def search_index_from_docs(source_chunks):
197
  # Create index from chunk documents
198
  # print("Size of chunk" + str(len(source_chunks)))
199
  search_index = FAISS.from_texts([doc.page_content for doc in source_chunks], embeddings, metadatas=[doc.metadata for doc in source_chunks])
200
  return search_index
201
-
202
-
203
- def get_qa_chain(gpt_3_5_index):
204
- global gpt_3_5
205
- print("index: " + str(gpt_3_5_index))
206
- return ConversationalRetrievalChain.from_llm(gpt_3_5, chain_type="stuff", get_chat_history=get_chat_history,
207
- retriever=gpt_3_5_index.as_retriever(), return_source_documents=True, verbose=True)
208
-
209
- def get_chat_history(inputs) -> str:
210
- res = []
211
- for human, ai in inputs:
212
- res.append(f"Human:{human}\nAI:{ai}")
213
- return "\n".join(res)
214
-
215
-
216
- def generate_answer(question) -> str:
217
- global chat_history, gpt_3_5_index
218
- gpt_3_5_chain = get_qa_chain(gpt_3_5_index)
219
- result = gpt_3_5_chain(
220
- {"question": question, "chat_history": chat_history,"vectordbkwargs": {"search_distance": 0.8}})
221
- print("REsult: " + str(result))
222
- chat_history = [(question, result["answer"])]
223
- sources = []
224
-
225
- for document in result['source_documents']:
226
- source = document.metadata['source']
227
- sources.append(source)
228
-
229
- source = ',\n'.join(set(sources))
230
- return result['answer'] + '\nSOURCES: ' + source
231
-
232
-
233
- def get_agent_chain(prompt, tools):
234
- global gpt_3_5
235
- # output_parser = CustomOutputParser()
236
- llm_chain = LLMChain(llm=gpt_3_5, prompt=prompt)
237
- agent = ConversationalAgent(llm_chain=llm_chain, tools=tools, verbose=True)
238
- agent_chain = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True, memory=memory,
239
- intermediate_steps=True)
240
- return agent_chain
241
-
242
-
243
- def get_prompt_and_tools():
244
- tools = get_tools()
245
-
246
- prefix = """Have a conversation with a human, answering the following questions as best you can.
247
- Always try to use Vectorstore first.
248
- Your name is Makerlab Bot because you are a personal assistant of Makerlab. You have access to the following tools:"""
249
- suffix = """Begin! If you use any tool, ALWAYS return a "SOURCES" part in your answer"
250
-
251
- {chat_history}
252
- Question: {input}
253
- {agent_scratchpad}
254
- SOURCES:"""
255
- prompt = ConversationalAgent.create_prompt(
256
- tools,
257
- prefix=prefix,
258
- suffix=suffix,
259
- input_variables=["input", "chat_history", "agent_scratchpad"]
260
- )
261
- # print("Template: " + prompt.template)
262
- return prompt, tools
263
-
264
-
265
- def get_tools():
266
- tools = [
267
- Tool(
268
- name="Vectorstore",
269
- func=generate_answer,
270
- description="useful for when you need to answer questions about the Makerlab or 3D Printing.",
271
- return_direct=True
272
- )]
273
- return tools
274
-
275
- def get_custom_agent(prompt, tools):
276
-
277
- llm_chain = LLMChain(llm=gpt_3_5, prompt=prompt)
278
-
279
- output_parser = CustomOutputParser()
280
- tool_names = [tool.name for tool in tools]
281
- agent = LLMSingleActionAgent(
282
- llm_chain=llm_chain,
283
- output_parser=output_parser,
284
- stop=["\nObservation:"],
285
- allowed_tools=tool_names
286
- )
287
- agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True, memory=memory,
288
- intermediate_steps=True)
289
- return agent_executor
290
-
291
- def get_prompt_and_tools_for_custom_agent():
292
- template = """
293
- Have a conversation with a human, answering the following questions as best you can.
294
- Always try to use Vectorstore first.
295
- Your name is Makerlab Bot because you are a personal assistant of Makerlab. You have access to the following tools:
296
-
297
- {tools}
298
-
299
- To answer for the new input, use the following format:
300
-
301
- New Input: the input question you must answer
302
- Thought: Do I need to use a tool? Yes
303
- Action: the action to take, should be one of [{tool_names}]
304
- Action Input: the input to the action
305
- Observation: the result of the action
306
- ... (this Thought/Action/Action Input/Observation can repeat N times)
307
- Thought: I now know the final answer
308
- Final Answer: the final answer to the original input question. SOURCES: the sources referred to find the final answer
309
-
310
-
311
- When you have a response to say to the Human and DO NOT need to use a tool:
312
- 1. DO NOT return "SOURCES" if you did not use any tool.
313
- 2. You MUST use this format:
314
- ```
315
- Thought: Do I need to use a tool? No
316
- AI: [your response here]
317
- ```
318
-
319
- Begin! Remember to speak as a personal assistant when giving your final answer.
320
- ALWAYS return a "SOURCES" part in your answer, if you used any tool.
321
-
322
- Previous conversation history:
323
- {chat_history}
324
- New input: {input}
325
- {agent_scratchpad}
326
- SOURCES:"""
327
- tools = get_tools()
328
- prompt = CustomPromptTemplate(
329
- template=template,
330
- tools=tools,
331
- # This omits the `agent_scratchpad`, `tools`, and `tool_names` variables because those are generated dynamically
332
- # This includes the `intermediate_steps` variable because that is needed
333
- input_variables=["input", "intermediate_steps", "chat_history"]
334
- )
335
- return prompt, tools
 
1
  import os
2
  import pickle
 
3
  import time
 
4
  from urllib.parse import urlparse, urljoin
5
 
6
  import faiss
7
  import requests
8
  from PyPDF2 import PdfReader
9
  from bs4 import BeautifulSoup
 
 
 
 
 
10
  from langchain.docstore.document import Document
 
 
 
11
  from langchain.text_splitter import CharacterTextSplitter
12
  from langchain.vectorstores.faiss import FAISS
13
 
14
  book_url = 'https://g.co/kgs/2VFC7u'
15
  book_file = "Book.pdf"
16
  url = 'https://makerlab.illinois.edu/'
17
+ def get_search_index(pickle_file, index_file, embeddings):
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  if os.path.isfile(pickle_file) and os.path.isfile(index_file) and os.path.getsize(pickle_file) > 0:
20
  # Load index from pickle file
21
  with open(pickle_file, "rb") as f:
22
  search_index = pickle.load(f)
23
  else:
24
+ source_chunks = create_chunk_documents()
25
 
26
+ search_index = search_index_from_docs(source_chunks, embeddings=embeddings)
27
 
28
+ faiss.write_index(search_index.index, index_file)
29
+
30
+ # Save index to pickle file
31
+ with open(pickle_file, "wb") as f:
32
+ pickle.dump(search_index, f)
33
 
 
 
 
 
 
 
 
34
  return search_index
35
 
36
 
 
118
  # print("document list" + str(len(document_list)))
119
  return document_list
120
 
121
+ def search_index_from_docs(source_chunks, embeddings):
122
  # Create index from chunk documents
123
  # print("Size of chunk" + str(len(source_chunks)))
124
  search_index = FAISS.from_texts([doc.page_content for doc in source_chunks], embeddings, metadatas=[doc.metadata for doc in source_chunks])
125
  return search_index
126
+ def generate_answer(chain, index, question):
127
+ #Get answer
128
+ answer = chain(
129
+ {
130
+ "input_documents": index.similarity_search(question, k=4),
131
+ "question": question,
132
+ },
133
+ return_only_outputs=True,
134
+ )["output_text"]
135
+
136
+ return answer