akshansh36 commited on
Commit
4cfe125
·
verified ·
1 Parent(s): 48f2a44

changed logic, included RAG

Browse files
Files changed (1) hide show
  1. app.py +153 -46
app.py CHANGED
@@ -6,13 +6,31 @@ import datetime
6
  from pymongo import MongoClient
7
  from bson import ObjectId
8
  from dotenv import load_dotenv
 
9
  from langchain_google_genai import GoogleGenerativeAIEmbeddings
10
  from langchain_google_genai import ChatGoogleGenerativeAI
11
  from langchain_core.prompts import ChatPromptTemplate
12
-
13
  st.set_page_config(layout="wide", page_title="IOCL Chatbot", page_icon="📄")
14
  load_dotenv()
15
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  # MongoDB connection setup
17
  MONGO_URI = os.getenv("MONGO_URI")
18
  client = MongoClient(MONGO_URI)
@@ -25,9 +43,6 @@ embeddings = GoogleGenerativeAIEmbeddings(model="models/embedding-001", google_a
25
  llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0, max_tokens=None, google_api_key=FLASH_API)
26
 
27
  # Load the extracted JSON data
28
- with open('iocl_extracted_2.json', 'r') as file:
29
- extracted_data = json.load(file)
30
- reference_data = json.dumps(extracted_data)
31
 
32
  # Initialize session state for current chat session
33
  if 'current_chat_id' not in st.session_state:
@@ -57,14 +72,13 @@ def load_chat_session(session_id):
57
  st.session_state['chat_history'] = session['messages']
58
 
59
 
60
-
61
  # Function to update chat session in MongoDB (store last 15 question-answer pairs)
62
  # Function to update chat session in MongoDB (store entire chat history)
63
- def update_chat_session(session_id, question, answer):
64
  # Append the new question-answer pair to the full messages array
65
  chat_sessions.update_one(
66
  {"_id": ObjectId(session_id)},
67
- {"$push": {"messages": {"$each": [{"question": question, "answer": answer}]}}}
68
  )
69
 
70
 
@@ -78,78 +92,146 @@ def replace_last_response_in_mongo(session_id, new_answer):
78
  {"$set": {f"messages.{last_message_index}.answer": new_answer}}
79
  )
80
 
 
81
  # Function to regenerate the response
82
  def regenerate_response():
83
- if st.session_state['chat_history']:
84
- last_question = st.session_state['chat_history'][-1]["question"] # Get the last question
85
- # Exclude the last response from the history when sending the question to LLM
86
- previous_history = st.session_state['chat_history'][:-1] # Exclude the last Q&A pair
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
- with st.spinner("Please wait, regenerating the response!"):
89
- # Generate a new response for the last question using only the previous history
90
- new_reply = generate_summary(str(reference_data), last_question, previous_history)
91
 
92
- # Replace the last response in the session state with the new reply
93
- st.session_state['chat_history'][-1]["answer"] = new_reply
94
 
95
- # Update MongoDB with the new response
96
- if st.session_state['current_chat_id']:
97
- replace_last_response_in_mongo(st.session_state['current_chat_id'], new_reply)
98
 
99
- st.session_state['regenerate'] = False # Reset regenerate flag
100
- st.rerun()
 
 
 
101
 
102
 
103
- # Function to generate a detailed response based on the query and JSON data
104
 
105
 
106
  # When generating a response, pass only the latest 15 messages to the LLM
107
- def generate_summary(reference_data, query, chat_history):
108
  try:
109
- # Escape curly braces in the JSON data to avoid conflicts with prompt placeholders
110
- escaped_reference_data = reference_data.replace("{", "{{").replace("}", "}}")
111
-
112
  # Limit the history sent to the LLM to the latest 15 question-answer pairs
113
- limited_history = chat_history[-15:] if len(chat_history) > 15 else chat_history
114
 
115
  # Create conversation history for the LLM, only using the last 15 entries
116
- history_text = "\n".join([f"User: {q['question']}\nLLM: {q['answer']}" for q in limited_history])
117
 
118
  # Define the system and user prompts including the limited history
119
  prompt = ChatPromptTemplate.from_messages([
120
- ("system", """You are a chatbot who specialises in answering questions related to Indan Oil Corporation Limitied(IOCL).
121
- This is the extracted data from the Indian Oil Corporation Limited (IOCL) website. The extracted data contains detailed information about the company and its various operations. You will be provided with a query, and you must use this data to answer it comprehensively.
122
- Additionally, the conversation history may contain relevant context or prior queries and responses. Use this history to ensure your answer is accurate and coherent, building on previous information if necessary.
123
-
 
124
  Key Guidelines:
125
  1.Accuracy is paramount: If the extracted data or conversation history does not contain the information required to answer the query, clearly state, "The answer is not available in the context." Do not attempt to provide a speculative or incorrect response.
126
  2.Be detailed: Provide clear, concise, and thorough answers without omitting any relevant information from the extracted data.
127
  3.Avoid quoting field names: When responding, avoid directly quoting or referencing field names or formats from the extracted data. Instead, present the information naturally, as if summarizing or interpreting the data. Try to give the answer in points.
128
  4.Use the conversation history: When applicable, refer to earlier parts of the conversation to ensure consistency and accuracy in your response.
129
- 5.Sometime a query might be a followup question,without proper context in that case try using previous conversation history and try to utilise latest messages to answer it if possible.
130
  6.Answer the queries in conversational style.
131
- 7.Important - If any links or source PDFs links are available within the extracted data part which you are referring to answer the query, you must include that links in your responses, suggesting that users can refer to the links for more detailed information.
132
  """),
133
  ("human", f'''
 
 
134
  "Query":\n {query}\n
135
- "Previous Conversation History": \n{history_text}\n
136
- "Extracted Data": \n{escaped_reference_data}\n
137
-
138
  '''
139
  )
140
  ])
141
 
142
  # Chain the prompt with LLM for response generation
143
  chain = prompt | llm
144
- result = chain.invoke({"Extracted Data": escaped_reference_data, "Query": query})
145
 
146
  # Return the generated response
 
147
  return result.content
148
 
149
  except Exception as e:
150
  st.error(f"Error answering your question: {e}")
151
- return "Error answering question."
 
 
 
 
 
 
 
 
 
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
 
155
  # Sidebar for showing chat sessions and creating new sessions
@@ -195,16 +277,41 @@ if user_question:
195
 
196
  with st.spinner("Please wait, I am thinking!!"):
197
  # Store the user's question and get the assistant's response
198
- reply = generate_summary(str(reference_data), user_question, st.session_state['chat_history'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
 
200
 
201
- # Append the new question-answer pair to chat history
202
- st.session_state['chat_history'].append({"question": user_question, "answer": reply})
 
203
 
204
- # Update the current chat session in MongoDB
205
- if st.session_state['current_chat_id']:
206
- update_chat_session(st.session_state['current_chat_id'], user_question, reply)
207
 
 
 
 
 
208
  # Display the updated chat history (show last 15 question-answer pairs)
209
  for i, pair in enumerate(st.session_state['chat_history']):
210
  question = pair["question"]
 
6
  from pymongo import MongoClient
7
  from bson import ObjectId
8
  from dotenv import load_dotenv
9
+ import pinecone
10
  from langchain_google_genai import GoogleGenerativeAIEmbeddings
11
  from langchain_google_genai import ChatGoogleGenerativeAI
12
  from langchain_core.prompts import ChatPromptTemplate
13
+ import re
14
  st.set_page_config(layout="wide", page_title="IOCL Chatbot", page_icon="📄")
15
  load_dotenv()
16
+ import logging
17
+
18
+ logging.basicConfig(
19
+ level=logging.DEBUG, # This is for your application logs
20
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
21
+ datefmt='%Y-%m-%d %H:%M:%S'
22
+ )
23
+
24
+ # Suppress pymongo debug logs by setting the pymongo logger to a higher level
25
+ pymongo_logger = logging.getLogger('pymongo')
26
+ pymongo_logger.setLevel(logging.WARNING)
27
+
28
+ PINECONE_API=os.getenv("PINECONE_API_KEY")
29
+ pc = pinecone.Pinecone(
30
+ api_key=PINECONE_API
31
+ )
32
+ index_name = "iocl"
33
+ index = pc.Index(index_name)
34
  # MongoDB connection setup
35
  MONGO_URI = os.getenv("MONGO_URI")
36
  client = MongoClient(MONGO_URI)
 
43
  llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0, max_tokens=None, google_api_key=FLASH_API)
44
 
45
  # Load the extracted JSON data
 
 
 
46
 
47
  # Initialize session state for current chat session
48
  if 'current_chat_id' not in st.session_state:
 
72
  st.session_state['chat_history'] = session['messages']
73
 
74
 
 
75
  # Function to update chat session in MongoDB (store last 15 question-answer pairs)
76
  # Function to update chat session in MongoDB (store entire chat history)
77
+ def update_chat_session(session_id, question, answer,improved_question):
78
  # Append the new question-answer pair to the full messages array
79
  chat_sessions.update_one(
80
  {"_id": ObjectId(session_id)},
81
+ {"$push": {"messages": {"$each": [{"question": question,'improved_question':improved_question,"answer": answer}]}}}
82
  )
83
 
84
 
 
92
  {"$set": {f"messages.{last_message_index}.answer": new_answer}}
93
  )
94
 
95
+
96
  # Function to regenerate the response
97
  def regenerate_response():
98
+ try:
99
+ if st.session_state['chat_history']:
100
+ last_question = st.session_state['chat_history'][-1]["question"] # Get the last question
101
+ # Exclude the last response from the history when sending the question to LLM
102
+ previous_history = st.session_state['chat_history'][:-1] # Exclude the last Q&A pair
103
+
104
+ with st.spinner("Please wait, regenerating the response!"):
105
+ # Generate a new response for the last question using only the previous history
106
+
107
+
108
+ query = get_context_from_messages(last_question, previous_history)
109
+ if query:
110
+ logging.info(f"Extracted query is :{query}\n")
111
+ extracted_query = get_query_from_llm_answer(query)
112
+ if extracted_query:
113
+ query = extracted_query
114
+ else:
115
+ query = last_question
116
+
117
+ query_embedding = embeddings.embed_query(query)
118
+ search_results = index.query(vector=query_embedding, top_k=5, include_metadata=True)
119
+ matches = search_results['matches']
120
+
121
+ content = ""
122
+ for i, match in enumerate(matches):
123
+ chunk = match['metadata']['chunk']
124
+ url = match['metadata']['url']
125
+ content += f"chunk{i}: {chunk}\n" + f"url{i}: {url}\n"
126
+
127
+ new_reply= generate_summary(content, query, previous_history)
128
 
 
 
 
129
 
130
+ st.session_state['chat_history'][-1]["answer"] = new_reply
 
131
 
132
+ # Update MongoDB with the new response
133
+ if st.session_state['current_chat_id']:
134
+ replace_last_response_in_mongo(st.session_state['current_chat_id'], new_reply)
135
 
136
+ st.session_state['regenerate'] = False # Reset regenerate flag
137
+ st.rerun()
138
+
139
+ except Exception as e:
140
+ st.error("Error occured in Regenerating response, please try again later.")
141
 
142
 
 
143
 
144
 
145
  # When generating a response, pass only the latest 15 messages to the LLM
146
+ def generate_summary(chunks, query, chat_history):
147
  try:
 
 
 
148
  # Limit the history sent to the LLM to the latest 15 question-answer pairs
149
+ limited_history = chat_history[-10:] if len(chat_history) > 10 else chat_history
150
 
151
  # Create conversation history for the LLM, only using the last 15 entries
152
+ history_text = "\n".join([f"User: {q['improved_question']}\nLLM: {q['answer']}" for q in limited_history])
153
 
154
  # Define the system and user prompts including the limited history
155
  prompt = ChatPromptTemplate.from_messages([
156
+ ("system", """You are a chatbot who specialises in answering user queries related to Indan Oil Corporation Limitied(IOCL).
157
+ this is the extracted chunks of data from the Indian Oil Corporation Limited (IOCL) website. You will be provided with a query, and you must use these chunks of data to answer it comprehensively.
158
+ Each chunk of data has website source page urls associated to it, you must include these relevant urls in your answer telling the source.
159
+ Additionally, the conversation history is also provided which may contain relevant context or prior queries and responses. Use this history to ensure your answer is accurate and coherent, building on previous information if necessary.
160
+
161
  Key Guidelines:
162
  1.Accuracy is paramount: If the extracted data or conversation history does not contain the information required to answer the query, clearly state, "The answer is not available in the context." Do not attempt to provide a speculative or incorrect response.
163
  2.Be detailed: Provide clear, concise, and thorough answers without omitting any relevant information from the extracted data.
164
  3.Avoid quoting field names: When responding, avoid directly quoting or referencing field names or formats from the extracted data. Instead, present the information naturally, as if summarizing or interpreting the data. Try to give the answer in points.
165
  4.Use the conversation history: When applicable, refer to earlier parts of the conversation to ensure consistency and accuracy in your response.
 
166
  6.Answer the queries in conversational style.
167
+ 7.It is must to include urls present in the chunk which you are using to formulate your ansewer.
168
  """),
169
  ("human", f'''
170
+ Previous Conversation History: \n{history_text}\n
171
+ "Extracted Data": \n{chunks}\n
172
  "Query":\n {query}\n
 
 
 
173
  '''
174
  )
175
  ])
176
 
177
  # Chain the prompt with LLM for response generation
178
  chain = prompt | llm
179
+ result = chain.invoke({"Previous Concversation History":history_text,"Extracted Data": chunks, "Query": query})
180
 
181
  # Return the generated response
182
+ logging.info(f"LLM answer is :{result}")
183
  return result.content
184
 
185
  except Exception as e:
186
  st.error(f"Error answering your question: {e}")
187
+ return None
188
+
189
+
190
+ def get_context_from_messages(query,chat_history):
191
+ try:
192
+
193
+ logging.info(f"Getting context from original query: {query}")
194
+
195
+ # Limit the history sent to the LLM to the latest 15 question-answer pairs
196
+ limited_history = chat_history[-3:] if len(chat_history) > 3 else chat_history
197
 
198
+ # Create conversation history for the LLM, only using the last 15 entries
199
+ history_text = "\n".join([f"User: {q['question']}\nLLM: {q['answer']}" for q in limited_history])
200
+
201
+ # Define the system and user prompts including the limited history
202
+ prompt = ChatPromptTemplate.from_messages([
203
+ ("system", """"I will provide you with a user query and up to the last 3 messages from the chat history, including both questions and answers. Your task is to determine whether the provided user query is self-contained (i.e., it can be answered directly without relying on prior messages) or a follow-up query that depends on the previous context.
204
+ 1. If the query is self-contained, return None
205
+ 2. If the query is a follow-up, use the provided chat history to reconstruct a well-defined, contextually complete query that can stand alone."
206
+
207
+ I have provided an output format below, stricly follow it. Do not give anything else other than just the output.
208
+ expected_output_format: "query: String or None"
209
+ """),
210
+ ("human", f'''
211
+ "Query":\n {query}\n
212
+ Previous Conversation History: \n{history_text}\n
213
+ '''
214
+ )
215
+ ])
216
+
217
+ # Chain the prompt with LLM for response generation
218
+ chain = prompt | llm
219
+ result = chain.invoke({"Query": query,"Previous Conversation History":history_text})
220
+ logging.info(f"llm answer for query extraction is :{result}")
221
+
222
+ # Return the generated response
223
+ return result.content
224
+
225
+ except Exception as e:
226
+ logging.error(f"exception occured in getting query from original query :{e}")
227
+ return None
228
+
229
+ def get_query_from_llm_answer(llm_output):
230
+ match = re.search(r'query:\s*(.*)', llm_output)
231
+ if match:
232
+ query = match.group(1).strip().strip('"') # Remove leading/trailing spaces and quotes
233
+ return None if query.lower() == "none" else query
234
+ return None
235
 
236
 
237
  # Sidebar for showing chat sessions and creating new sessions
 
277
 
278
  with st.spinner("Please wait, I am thinking!!"):
279
  # Store the user's question and get the assistant's response
280
+ query=get_context_from_messages(user_question,st.session_state['chat_history'])
281
+ if query:
282
+ logging.info(f"Extracted query is :{query}\n")
283
+ extracted_query=get_query_from_llm_answer(query)
284
+ if extracted_query:
285
+ query=extracted_query
286
+ else:
287
+ query=user_question
288
+
289
+ query_embedding=embeddings.embed_query(query)
290
+ search_results = index.query(vector=query_embedding, top_k=5, include_metadata=True)
291
+ matches=search_results['matches']
292
+
293
+ content=""
294
+ for i,match in enumerate(matches):
295
+ chunk=match['metadata']['chunk']
296
+ url=match['metadata']['url']
297
+ content += f"chunk{i}: {chunk}\n" + f"url{i}: {url}\n"
298
+
299
+
300
 
301
+ reply = generate_summary(content, query, st.session_state['chat_history'])
302
 
303
+ if reply:
304
+ # Append the new question-answer pair to chat history
305
+ st.session_state['chat_history'].append({"question": user_question, "answer": reply,"improved_question":query})
306
 
307
+ # Update the current chat session in MongoDB
308
+ if st.session_state['current_chat_id']:
309
+ update_chat_session(st.session_state['current_chat_id'], user_question, reply,query)
310
 
311
+ else:
312
+ st.error("Error processing your request, Please try again later.")
313
+ else:
314
+ st.error("Error processing your request, Please try again later.")
315
  # Display the updated chat history (show last 15 question-answer pairs)
316
  for i, pair in enumerate(st.session_state['chat_history']):
317
  question = pair["question"]