Sadiaa commited on
Commit
49c055c
Β·
verified Β·
1 Parent(s): d18fcb7

Update chatbot.py

Browse files
Files changed (1) hide show
  1. chatbot.py +46 -16
chatbot.py CHANGED
@@ -1,6 +1,7 @@
1
  import os
2
  import time
3
  import json
 
4
  from groq import Groq
5
  from langchain.memory import ConversationBufferMemory
6
  from langchain_openai import ChatOpenAI
@@ -8,9 +9,13 @@ from langchain_community.document_loaders import CSVLoader
8
  from langchain_community.vectorstores import FAISS
9
  from deep_translator import GoogleTranslator
10
 
 
 
 
11
 
12
  class Comsatsbot:
13
  def __init__(self, hf, llm, api_keys, chats_collection, paths, index_path='faiss_kb'):
 
14
  self.llm = llm
15
  self.api_keys = api_keys
16
  self.client = None
@@ -29,53 +34,71 @@ class Comsatsbot:
29
  self.initialize_faiss_index()
30
 
31
  def load_data(self, paths):
 
32
  documents = []
33
  for path in paths:
34
  loader = CSVLoader(file_path=path)
35
  data = loader.load()
36
  documents.extend(data)
 
37
  return documents
38
 
39
  def initialize_faiss_index(self):
 
40
  if os.path.exists(self.index_path):
 
41
  self.faiss_index = FAISS.load_local(self.index_path, self.hf, allow_dangerous_deserialization=True)
42
  else:
 
43
  documents = self.load_data(self.paths)
44
  self.faiss_index = FAISS.from_documents(documents, self.hf)
45
  self.faiss_index.save_local(self.index_path)
46
  self.faiss_retriever = self.faiss_index.as_retriever(search_kwargs={"k": 5})
 
47
 
48
  def retrieve_answer(self, query):
 
49
  if self.faiss_retriever:
50
- return self.faiss_retriever.invoke(query)
 
 
 
51
  return None
52
 
53
  def create_chat_record(self, chat_id):
 
54
  self.chats_collection.insert_one({
55
  "_id": chat_id,
56
  "history": []
57
  })
58
 
59
  def update_chat(self, chat_id, question, answer):
 
60
  self.chats_collection.update_one(
61
  {"_id": chat_id},
62
  {"$push": {"history": {"question": question, "answer": answer}}}
63
  )
64
 
65
  def load_chat(self, chat_id):
 
66
  chat_record = self.chats_collection.find_one({"_id": chat_id})
67
  if not chat_record:
 
68
  raise KeyError(f"Chat ID {chat_id} does not exist.")
69
  return chat_record.get('history', [])
70
 
71
  def new_chat(self, chat_id):
 
72
  if self.chats_collection.find_one({"_id": chat_id}):
 
73
  raise KeyError(f"Chat ID {chat_id} exists already.")
74
  self.create_chat_record(chat_id)
75
  return "success"
76
 
77
  def delete_chat(self, chat_id):
 
78
  if not self.chats_collection.find_one({"_id": chat_id}):
 
79
  raise KeyError(f"Chat ID {chat_id} does not exist.")
80
  self.chats_collection.delete_one({"_id": chat_id})
81
  return "success"
@@ -83,40 +106,32 @@ class Comsatsbot:
83
  def get_system_prompt(self):
84
  return """
85
  You are a comsats assistant to help the user with comsats university-related queries. Your response should be concise, direct, and to the point. Avoid any unnecessary explanations. Always consider the provided context and chat history to generate the answer.
86
-
87
  Use emojis only when required based on the user's tone and emotions. Do not overuse them. Here's when you should use emojis:
88
  - **Happy emotions**: Use 😊 or πŸ˜„ when the user expresses satisfaction or asks for something positive.
89
  - **Sad emotions**: Use πŸ˜” when the user is asking about something disappointing or negative.
90
  - **Surprise**: Use 😯 when the user expresses surprise.
91
  - **Anger or frustration**: Use 😑 when the user expresses frustration or dissatisfaction.
92
-
93
  If the user asks the same question repeatedly or asks an illogical question, feel free to use emojis to subtly convey frustration, confusion, or amusement.
94
-
95
  Do not include the phrase "According to the provided context" or "Based on the chat history". Simply generate the answer like a human would, without referencing where the information comes from.
96
-
97
  If the question requires a URL, format it like this:
98
  [Click here to visit COMSATS](https://comsats.edu.pk).
99
-
100
  Your task is to help students at COMSATS University, Attock campus, with their university-related queries. The following are key details about the university:
101
  - Departments: CS, AI, SE, Math, BBA, EE, CE, English.
102
  - Facilities: Cricket ground, football ground, two canteens (near CS and Math/EE), mosque near CS department, LT rooms in CS, classrooms in Math, and labs in EE.
103
  - Admission: Accepts NTS test, CGPA requirements: 85% for CGPA 4.0, 79-84% for CGPA 3.66.
104
  - Available degrees: BS Computer Science, BS Software Engineering, BS Artificial Intelligence, BS English, BS Math, BS Electrical Engineering, BS Computer Engineering, BS BBA.
105
-
106
  Consider the following chat history for additional context to answer the question:
107
  {history}
108
-
109
  When answering:
110
  - Answer in a conversational and friendly tone.
111
  - Be concise and to the point, while still being helpful.
112
  - If you don’t know the answer from the context or chat history, simply say "I don’t know the answer to this πŸ˜”".
113
-
114
  Context ends here. Now, answer the following question:
115
-
116
  {question}
117
  """
118
 
119
  def generate_response(self, question, history, context):
 
120
  prompt = self.get_system_prompt().format(question=question, history=history, context=context)
121
 
122
  while True:
@@ -124,6 +139,7 @@ Context ends here. Now, answer the following question:
124
  self.client = Groq(api_key=api_key)
125
  for model in self.models:
126
  try:
 
127
  chat_completion = self.client.chat.completions.create(
128
  messages=[
129
  {"role": "system", "content": prompt},
@@ -132,13 +148,18 @@ Context ends here. Now, answer the following question:
132
  model=model,
133
  max_tokens=1024,
134
  )
135
- return chat_completion.choices[0].message.content
136
- except Exception:
 
 
 
137
  time.sleep(2)
138
  continue
 
139
  return "Sorry, unable to provide an answer at this time."
140
 
141
  def detect_language(self, question):
 
142
  for api_key in self.api_keys:
143
  self.client = Groq(api_key=api_key)
144
  for model in self.models:
@@ -162,13 +183,18 @@ Context ends here. Now, answer the following question:
162
  response_format={"type": "json_object"},
163
  )
164
  response = json.loads(chat_completion.choices[0].message.content)
165
- return response['detected_language'].lower()
166
- except Exception:
 
 
 
167
  time.sleep(2)
168
  continue
 
169
  return "english"
170
 
171
  def translate_urdu(self, text):
 
172
  for api_key in self.api_keys:
173
  self.client = Groq(api_key=api_key)
174
  for model in self.models:
@@ -192,13 +218,17 @@ Context ends here. Now, answer the following question:
192
  response_format={"type": "json_object"},
193
  )
194
  response = json.loads(chat_completion.choices[0].message.content)
195
- return response['text']
196
- except Exception:
 
 
 
197
  time.sleep(2)
198
  continue
199
  return text
200
 
201
  def response(self, question, chat_id):
 
202
  chat_history = self.load_chat(chat_id)
203
 
204
  for entry in chat_history:
 
1
  import os
2
  import time
3
  import json
4
+ import logging
5
  from groq import Groq
6
  from langchain.memory import ConversationBufferMemory
7
  from langchain_openai import ChatOpenAI
 
9
  from langchain_community.vectorstores import FAISS
10
  from deep_translator import GoogleTranslator
11
 
12
+ # Set up logging
13
+ logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
14
+ logger = logging.getLogger(__name__)
15
 
16
  class Comsatsbot:
17
  def __init__(self, hf, llm, api_keys, chats_collection, paths, index_path='faiss_kb'):
18
+ logger.info("Initializing Comsatsbot...")
19
  self.llm = llm
20
  self.api_keys = api_keys
21
  self.client = None
 
34
  self.initialize_faiss_index()
35
 
36
  def load_data(self, paths):
37
+ logger.info(f"Loading data from paths: {paths}")
38
  documents = []
39
  for path in paths:
40
  loader = CSVLoader(file_path=path)
41
  data = loader.load()
42
  documents.extend(data)
43
+ logger.debug(f"Loaded {len(documents)} documents.")
44
  return documents
45
 
46
  def initialize_faiss_index(self):
47
+ logger.info("Initializing FAISS index...")
48
  if os.path.exists(self.index_path):
49
+ logger.info(f"FAISS index found at {self.index_path}. Loading...")
50
  self.faiss_index = FAISS.load_local(self.index_path, self.hf, allow_dangerous_deserialization=True)
51
  else:
52
+ logger.info(f"FAISS index not found. Creating a new one...")
53
  documents = self.load_data(self.paths)
54
  self.faiss_index = FAISS.from_documents(documents, self.hf)
55
  self.faiss_index.save_local(self.index_path)
56
  self.faiss_retriever = self.faiss_index.as_retriever(search_kwargs={"k": 5})
57
+ logger.info("FAISS index initialized successfully.")
58
 
59
  def retrieve_answer(self, query):
60
+ logger.info(f"Retrieving answer for query: {query}")
61
  if self.faiss_retriever:
62
+ result = self.faiss_retriever.invoke(query)
63
+ logger.debug(f"Retrieved answer: {result}")
64
+ return result
65
+ logger.warning("FAISS retriever is not initialized.")
66
  return None
67
 
68
  def create_chat_record(self, chat_id):
69
+ logger.info(f"Creating new chat record for chat_id: {chat_id}")
70
  self.chats_collection.insert_one({
71
  "_id": chat_id,
72
  "history": []
73
  })
74
 
75
  def update_chat(self, chat_id, question, answer):
76
+ logger.info(f"Updating chat history for chat_id: {chat_id}")
77
  self.chats_collection.update_one(
78
  {"_id": chat_id},
79
  {"$push": {"history": {"question": question, "answer": answer}}}
80
  )
81
 
82
  def load_chat(self, chat_id):
83
+ logger.info(f"Loading chat history for chat_id: {chat_id}")
84
  chat_record = self.chats_collection.find_one({"_id": chat_id})
85
  if not chat_record:
86
+ logger.error(f"Chat ID {chat_id} does not exist.")
87
  raise KeyError(f"Chat ID {chat_id} does not exist.")
88
  return chat_record.get('history', [])
89
 
90
  def new_chat(self, chat_id):
91
+ logger.info(f"Creating new chat with ID: {chat_id}")
92
  if self.chats_collection.find_one({"_id": chat_id}):
93
+ logger.error(f"Chat ID {chat_id} already exists.")
94
  raise KeyError(f"Chat ID {chat_id} exists already.")
95
  self.create_chat_record(chat_id)
96
  return "success"
97
 
98
  def delete_chat(self, chat_id):
99
+ logger.info(f"Deleting chat record for chat_id: {chat_id}")
100
  if not self.chats_collection.find_one({"_id": chat_id}):
101
+ logger.error(f"Chat ID {chat_id} does not exist.")
102
  raise KeyError(f"Chat ID {chat_id} does not exist.")
103
  self.chats_collection.delete_one({"_id": chat_id})
104
  return "success"
 
106
  def get_system_prompt(self):
107
  return """
108
  You are a comsats assistant to help the user with comsats university-related queries. Your response should be concise, direct, and to the point. Avoid any unnecessary explanations. Always consider the provided context and chat history to generate the answer.
 
109
  Use emojis only when required based on the user's tone and emotions. Do not overuse them. Here's when you should use emojis:
110
  - **Happy emotions**: Use 😊 or πŸ˜„ when the user expresses satisfaction or asks for something positive.
111
  - **Sad emotions**: Use πŸ˜” when the user is asking about something disappointing or negative.
112
  - **Surprise**: Use 😯 when the user expresses surprise.
113
  - **Anger or frustration**: Use 😑 when the user expresses frustration or dissatisfaction.
 
114
  If the user asks the same question repeatedly or asks an illogical question, feel free to use emojis to subtly convey frustration, confusion, or amusement.
 
115
  Do not include the phrase "According to the provided context" or "Based on the chat history". Simply generate the answer like a human would, without referencing where the information comes from.
 
116
  If the question requires a URL, format it like this:
117
  [Click here to visit COMSATS](https://comsats.edu.pk).
 
118
  Your task is to help students at COMSATS University, Attock campus, with their university-related queries. The following are key details about the university:
119
  - Departments: CS, AI, SE, Math, BBA, EE, CE, English.
120
  - Facilities: Cricket ground, football ground, two canteens (near CS and Math/EE), mosque near CS department, LT rooms in CS, classrooms in Math, and labs in EE.
121
  - Admission: Accepts NTS test, CGPA requirements: 85% for CGPA 4.0, 79-84% for CGPA 3.66.
122
  - Available degrees: BS Computer Science, BS Software Engineering, BS Artificial Intelligence, BS English, BS Math, BS Electrical Engineering, BS Computer Engineering, BS BBA.
 
123
  Consider the following chat history for additional context to answer the question:
124
  {history}
 
125
  When answering:
126
  - Answer in a conversational and friendly tone.
127
  - Be concise and to the point, while still being helpful.
128
  - If you don’t know the answer from the context or chat history, simply say "I don’t know the answer to this πŸ˜”".
 
129
  Context ends here. Now, answer the following question:
 
130
  {question}
131
  """
132
 
133
  def generate_response(self, question, history, context):
134
+ logger.info(f"Generating response for question: {question}")
135
  prompt = self.get_system_prompt().format(question=question, history=history, context=context)
136
 
137
  while True:
 
139
  self.client = Groq(api_key=api_key)
140
  for model in self.models:
141
  try:
142
+ logger.info(f"Calling model {model} for response...")
143
  chat_completion = self.client.chat.completions.create(
144
  messages=[
145
  {"role": "system", "content": prompt},
 
148
  model=model,
149
  max_tokens=1024,
150
  )
151
+ response = chat_completion.choices[0].message.content
152
+ logger.debug(f"Received response: {response}")
153
+ return response
154
+ except Exception as e:
155
+ logger.error(f"Error with model {model}: {e}")
156
  time.sleep(2)
157
  continue
158
+ logger.warning("Unable to generate a response.")
159
  return "Sorry, unable to provide an answer at this time."
160
 
161
  def detect_language(self, question):
162
+ logger.info(f"Detecting language for question: {question}")
163
  for api_key in self.api_keys:
164
  self.client = Groq(api_key=api_key)
165
  for model in self.models:
 
183
  response_format={"type": "json_object"},
184
  )
185
  response = json.loads(chat_completion.choices[0].message.content)
186
+ detected_language = response['detected_language'].lower()
187
+ logger.debug(f"Detected language: {detected_language}")
188
+ return detected_language
189
+ except Exception as e:
190
+ logger.error(f"Error detecting language: {e}")
191
  time.sleep(2)
192
  continue
193
+ logger.warning("Unable to detect language.")
194
  return "english"
195
 
196
  def translate_urdu(self, text):
197
+ logger.info(f"Translating text to Urdu: {text}")
198
  for api_key in self.api_keys:
199
  self.client = Groq(api_key=api_key)
200
  for model in self.models:
 
218
  response_format={"type": "json_object"},
219
  )
220
  response = json.loads(chat_completion.choices[0].message.content)
221
+ translated_text = response['text']
222
+ logger.debug(f"Translated text: {translated_text}")
223
+ return translated_text
224
+ except Exception as e:
225
+ logger.error(f"Error translating text: {e}")
226
  time.sleep(2)
227
  continue
228
  return text
229
 
230
  def response(self, question, chat_id):
231
+ logger.info(f"Processing response for question: {question} (chat_id: {chat_id})")
232
  chat_history = self.load_chat(chat_id)
233
 
234
  for entry in chat_history: