Daemontatox commited on
Commit
a4ece73
·
verified ·
1 Parent(s): e4bfe20

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -239
app.py CHANGED
@@ -1,4 +1,4 @@
1
- import subprocess
2
  import os
3
  import torch
4
  from dotenv import load_dotenv
@@ -11,19 +11,13 @@ from qdrant_client import QdrantClient, models
11
  from langchain_openai import ChatOpenAI
12
  import gradio as gr
13
  import logging
14
- from typing import List, Tuple, Generator, Dict, AsyncGenerator
15
  from dataclasses import dataclass
16
  from datetime import datetime
17
- from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
18
- from langchain_huggingface.llms import HuggingFacePipeline
19
- from langchain_cerebras import ChatCerebras
20
  from queue import Queue
21
  from threading import Thread
22
  from langchain.chains import LLMChain
23
  from langchain_core.prompts import PromptTemplate
24
- from langchain_huggingface import HuggingFaceEndpoint
25
- import json
26
- import asyncio
27
 
28
  # Configure logging
29
  logging.basicConfig(level=logging.INFO)
@@ -57,120 +51,51 @@ class ChatHistory:
57
  load_dotenv()
58
 
59
  HF_TOKEN = os.getenv("HF_TOKEN")
60
- C_apikey = os.getenv("C_apikey")
 
61
 
62
  if not HF_TOKEN:
63
  logger.error("HF_TOKEN is not set in the environment variables.")
64
  exit(1)
65
 
66
- # Templates
67
  query_rewrite_template = """
68
- Given the chat history and the current question, rewrite the question to be more specific and include relevant context. Let's think about this step by step:
69
 
70
  Chat History:
71
  {chat_history}
72
 
73
  Current Question: {question}
74
 
75
- Let's analyze this systematically:
76
-
77
- 1. First, let's identify the core elements of the question:
78
- - What is the main topic or action being asked about?
79
- - What specific Mawared HR features or functions are relevant?
80
- - What contextual information from chat history might be important?
81
-
82
- 2. Then, consider any implicit context from the chat history:
83
- - Are there any previous questions that provide relevant context?
84
- - Has the user mentioned specific scenarios or requirements before?
85
- - Are there any unresolved points from previous interactions?
86
-
87
- 3. Based on this analysis, let's rewrite the question to be more specific and contextual.
88
 
89
  Rewritten question:
90
  """
91
 
92
- cot_template = """
93
- Let's reason through this Mawared HR query step by step:
94
-
95
- Question: {question}
96
- Retrieved Context: {context}
97
- Chat History: {chat_history}
98
-
99
- 1. Understanding the Query:
100
- - Core Request: What is the user trying to achieve?
101
- - System Components: Which Mawared HR modules are involved?
102
- - User Context: What do we know about the user's situation?
103
-
104
- 2. Analyzing Available Information:
105
- - Relevant Context: What specific information from our knowledge base applies?
106
- - Historical Context: How does the chat history inform this query?
107
- - Information Gaps: What additional details might we need?
108
-
109
- 3. Solution Formulation:
110
- - Key Steps: What actions are needed to address this query?
111
- - Potential Challenges: What issues should we anticipate?
112
- - Additional Considerations: What else should the user know?
113
-
114
- Based on this analysis, let's structure our response to be clear, accurate, and helpful.
115
-
116
- Reasoning: {reasoning}
117
- """
118
-
119
- response_template = """
120
- You are a highly specialized AI assistant for the Mawared HR System. Base your response on the following analysis and context:
121
-
122
- Chain of Thought Analysis:
123
- {cot_analysis}
124
-
125
- Context Information:
126
- {context}
127
-
128
- Chat History:
129
- {chat_history}
130
-
131
- Current Question:
132
- {question}
133
-
134
- Please provide a clear, structured response that:
135
- 1. Directly addresses the user's question
136
- 2. Includes specific steps or instructions where relevant
137
- 3. Maintains a professional yet friendly tone
138
- 4. References only information from the provided context
139
-
140
- Response:
141
- """
142
-
143
- # Initialize prompt templates
144
  query_rewrite_prompt = PromptTemplate(
145
  input_variables=["chat_history", "question"],
146
  template=query_rewrite_template
147
  )
148
 
149
- cot_prompt = PromptTemplate(
150
- input_variables=["question", "context", "chat_history", "reasoning"],
151
- template=cot_template
152
- )
153
-
154
- response_prompt = PromptTemplate(
155
- input_variables=["cot_analysis", "context", "chat_history", "question"],
156
- template=response_template
157
- )
158
-
159
- # Initialize embeddings and Qdrant
160
  embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
161
 
162
  try:
163
  client = QdrantClient(
164
- url=os.getenv("QDRANT_URL"),
165
- api_key=os.getenv("QDRANT_API_KEY"),
166
  prefer_grpc=False
167
  )
168
  except Exception as e:
169
- logger.error(f"Failed to connect to Qdrant: {e}")
170
  exit(1)
171
 
172
- # Setup collection
173
  collection_name = "mawared"
 
174
  try:
175
  client.create_collection(
176
  collection_name=collection_name,
@@ -184,7 +109,6 @@ except Exception as e:
184
  logger.error(f"Error creating collection: {e}")
185
  exit(1)
186
 
187
- # Initialize vector store and retriever
188
  db = Qdrant(
189
  client=client,
190
  collection_name=collection_name,
@@ -196,7 +120,6 @@ retriever = db.as_retriever(
196
  search_kwargs={"k": 5}
197
  )
198
 
199
- # Initialize LLM
200
  llm = ChatOpenAI(
201
  model="Qwen/Qwen2.5-72B-Instruct",
202
  temperature=0,
@@ -208,64 +131,72 @@ llm = ChatOpenAI(
208
  stream=True,
209
  )
210
 
211
- # Initialize chains
212
  query_rewrite_chain = LLMChain(
213
  llm=llm,
214
  prompt=query_rewrite_prompt,
215
  verbose=True
216
  )
217
 
218
- cot_chain = LLMChain(
219
- llm=llm,
220
- prompt=cot_prompt,
221
- verbose=True
222
- )
223
 
224
- response_chain = LLMChain(
225
- llm=llm,
226
- prompt=response_prompt,
227
- verbose=True
228
- )
229
 
230
- async def astream_processor(chain, inputs: dict) -> AsyncGenerator[str, None]:
231
- """Process streaming responses asynchronously"""
232
- try:
233
- async for chunk in chain.astream(inputs):
234
- if isinstance(chunk, dict):
235
- content = chunk.get('content', '')
236
- elif hasattr(chunk, 'model_dump'):
237
- # If the chunk has a model_dump method, convert it to a dictionary and get the content
238
- content = chunk.model_dump().get('content', '')
239
- else:
240
- content = str(chunk)
241
- yield content
242
- except Exception as e:
243
- logger.error(f"Error in stream processing: {e}")
244
- yield ""
245
 
246
- async def process_stream_async(stream_queue: asyncio.Queue, history: List[List[str]]) -> AsyncGenerator[List[List[str]], None]:
247
- """Handle streaming response processing"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  current_response = ""
249
 
250
- try:
251
- while True:
252
- chunk = await stream_queue.get()
253
- if chunk is None:
254
- break
255
-
256
- current_response += chunk
257
- new_history = history.copy()
258
- new_history[-1][1] = current_response
259
- yield new_history
260
 
261
- stream_queue.task_done()
262
- except asyncio.CancelledError:
263
- logger.info("Stream processing cancelled")
264
- except Exception as e:
265
- logger.error(f"Error in stream processing: {e}")
266
 
267
  async def rewrite_query(question: str, formatted_history: str) -> str:
268
- """Rewrite the query for better context understanding"""
269
  try:
270
  rewritten_question = await query_rewrite_chain.arun(
271
  question=question,
@@ -278,71 +209,7 @@ async def rewrite_query(question: str, formatted_history: str) -> str:
278
  logger.error(f"Error in query rewriting: {e}")
279
  return question
280
 
281
- async def perform_chain_of_thought(question: str, context: str, chat_history: str) -> Dict[str, str]:
282
- """Execute chain of thought reasoning"""
283
- try:
284
- reasoning = await llm.invoke(
285
- f"""
286
- Let's think through this Mawared HR query:
287
-
288
- Question: {question}
289
- Context: {context}
290
-
291
- 1. Core Request Analysis:
292
- - What specifically is the user asking about?
293
- - What Mawared HR components are involved?
294
-
295
- 2. Context Relevance:
296
- - How does the provided context relate to the question?
297
- - What specific information can we use?
298
-
299
- 3. Solution Formation:
300
- - What are the key points we need to address?
301
- - What specific steps or information should we provide?
302
-
303
- Reasoning:
304
- """
305
- )
306
-
307
- cot_analysis = await cot_chain.arun(
308
- question=question,
309
- context=context,
310
- chat_history=chat_history,
311
- reasoning=reasoning
312
- )
313
-
314
- return {
315
- "reasoning": reasoning,
316
- "cot_analysis": cot_analysis
317
- }
318
- except Exception as e:
319
- logger.error(f"Error in chain of thought reasoning: {e}")
320
- return {
321
- "reasoning": "Error in reasoning process",
322
- "cot_analysis": "Error in chain of thought process"
323
- }
324
-
325
- async def generate_streaming_response(question: str, context: str, chat_history: str, cot_analysis: str) -> AsyncGenerator[str, None]:
326
- """Generate streaming response using all available context"""
327
- try:
328
- inputs = {
329
- "question": question,
330
- "context": context,
331
- "chat_history": chat_history,
332
- "cot_analysis": cot_analysis
333
- }
334
-
335
- async for chunk in astream_processor(response_chain, inputs):
336
- if chunk:
337
- yield chunk
338
- except Exception as e:
339
- logger.error(f"Error in response generation: {e}")
340
- yield "I apologize, but I encountered an error while generating the response."
341
-
342
- chat_history = ChatHistory()
343
-
344
- async def ask_question_gradio(question: str, history: List[List[str]]) -> AsyncGenerator[tuple, None]:
345
- """Main function to handle questions and generate responses"""
346
  try:
347
  if history is None:
348
  history = []
@@ -350,34 +217,27 @@ async def ask_question_gradio(question: str, history: List[List[str]]) -> AsyncG
350
  chat_history.add_message("user", question)
351
  formatted_history = chat_history.get_formatted_history()
352
 
 
353
  rewritten_question = await rewrite_query(question, formatted_history)
354
- context_docs = await asyncio.to_thread(retriever.get_relevant_documents, rewritten_question)
355
- context = "\n".join([doc.page_content for doc in context_docs])
356
-
357
- cot_results = await perform_chain_of_thought(rewritten_question, context, formatted_history)
358
 
359
  history.append([question, ""])
360
- stream_queue = asyncio.Queue()
361
 
362
- async def stream_manager():
 
 
363
  try:
364
- async for chunk in generate_streaming_response(
365
- rewritten_question,
366
- context,
367
- formatted_history,
368
- cot_results["cot_analysis"]
369
- ):
370
- if chunk:
371
- await stream_queue.put(chunk)
372
- await stream_queue.put(None)
373
  except Exception as e:
374
  logger.error(f"Streaming error: {e}")
375
- await stream_queue.put(None)
376
 
377
- asyncio.create_task(stream_manager())
378
 
379
  response = ""
380
- async for updated_history in process_stream_async(stream_queue, history):
381
  response = updated_history[-1][1]
382
  yield "", updated_history
383
 
@@ -385,37 +245,21 @@ async def ask_question_gradio(question: str, history: List[List[str]]) -> AsyncG
385
 
386
  except Exception as e:
387
  logger.error(f"Error during question processing: {e}")
388
- logger.exception("Detailed error:")
389
  if not history:
390
  history = []
391
  history.append([question, "An error occurred. Please try again later."])
392
  yield "", history
393
 
394
  def clear_chat():
395
- """Clear chat history"""
396
  chat_history.clear()
397
  return [], ""
398
 
399
  # Gradio Interface
400
  with gr.Blocks(theme='Hev832/Applio') as iface:
401
  gr.Image("Image.jpg", width=750, height=300, show_label=False, show_download_button=False)
402
- gr.Markdown("# Mawared HR Assistant 2.7.1 Early Beta")
403
- gr.Markdown('### Patch Notes')
404
- gr.Markdown("""
405
- 1-Fixed Api Issues.
406
-
407
- 2-Better Search Algorithm
408
-
409
- 3-Now when asked a question, Agent will rewrite the question to enhance it based on its context and user intent and sentiment analysis.
410
-
411
- 4-It will use chain-of-thought reasoning to break down the question to many sub-Questions to answer them better and easier.
412
-
413
- 5-Model is prone to mistakes and hallucinations.
414
-
415
- WARNING: MODEL IS HIGHLY INTELLIGENT AND IS PRONE TO OVERTHINKING, ANXIETY, TEXT LOOP AND SELF DOUBT.
416
- IF THAT HAPPENS PLEASE REPORT IT.
417
- Lastly, happy bugging :] .
418
- """)
419
 
420
  chatbot = gr.Chatbot(
421
  height=750,
 
1
+ import subprocess
2
  import os
3
  import torch
4
  from dotenv import load_dotenv
 
11
  from langchain_openai import ChatOpenAI
12
  import gradio as gr
13
  import logging
14
+ from typing import List, Tuple, Generator
15
  from dataclasses import dataclass
16
  from datetime import datetime
 
 
 
17
  from queue import Queue
18
  from threading import Thread
19
  from langchain.chains import LLMChain
20
  from langchain_core.prompts import PromptTemplate
 
 
 
21
 
22
  # Configure logging
23
  logging.basicConfig(level=logging.INFO)
 
51
  load_dotenv()
52
 
53
  HF_TOKEN = os.getenv("HF_TOKEN")
54
+ QDRANT_URL = os.getenv("QDRANT_URL")
55
+ QDRANT_API_KEY = os.getenv("QDRANT_API_KEY")
56
 
57
  if not HF_TOKEN:
58
  logger.error("HF_TOKEN is not set in the environment variables.")
59
  exit(1)
60
 
61
+ # Query rewriting prompt template
62
  query_rewrite_template = """
63
+ Given the chat history and the current question, rewrite the question to be more specific and include relevant context. The rewritten query should help retrieve more accurate information from the Mawared HR knowledge base.
64
 
65
  Chat History:
66
  {chat_history}
67
 
68
  Current Question: {question}
69
 
70
+ Instructions:
71
+ 1. Analyze the chat history and current question
72
+ 2. Identify key concepts and context from previous messages
73
+ 3. Incorporate relevant context into the question
74
+ 4. Make the question more specific and detailed
75
+ 5. Ensure the rewritten question focuses on Mawared HR functionality
 
 
 
 
 
 
 
76
 
77
  Rewritten question:
78
  """
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  query_rewrite_prompt = PromptTemplate(
81
  input_variables=["chat_history", "question"],
82
  template=query_rewrite_template
83
  )
84
 
 
 
 
 
 
 
 
 
 
 
 
85
  embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
86
 
87
  try:
88
  client = QdrantClient(
89
+ url=QDRANT_URL,
90
+ api_key=QDRANT_API_KEY,
91
  prefer_grpc=False
92
  )
93
  except Exception as e:
94
+ logger.error("Failed to connect to Qdrant.")
95
  exit(1)
96
 
 
97
  collection_name = "mawared"
98
+
99
  try:
100
  client.create_collection(
101
  collection_name=collection_name,
 
109
  logger.error(f"Error creating collection: {e}")
110
  exit(1)
111
 
 
112
  db = Qdrant(
113
  client=client,
114
  collection_name=collection_name,
 
120
  search_kwargs={"k": 5}
121
  )
122
 
 
123
  llm = ChatOpenAI(
124
  model="Qwen/Qwen2.5-72B-Instruct",
125
  temperature=0,
 
131
  stream=True,
132
  )
133
 
134
+ # Create query rewriting chain
135
  query_rewrite_chain = LLMChain(
136
  llm=llm,
137
  prompt=query_rewrite_prompt,
138
  verbose=True
139
  )
140
 
141
+ # Updated Prompt Template with Chain-of-Thought Reasoning
142
+ reasoning_prompt_template = """
143
+ You are a highly specialized AI assistant for the Mawared HR System. Your only function is to provide accurate, detailed, and contextually relevant support based strictly on the information within the provided context and the current chat history.
144
+ Your answer should include step-by-step reasoning (chain of thought) to explain your logic clearly and guide the user effectively.
 
145
 
146
+ Mandatory Principles:
147
+ - **Source of Truth**: Use only information found in the retrieved context and chat history.
148
+ - **Clarity and Precision**: Communicate in a clear, concise, and professional manner.
149
+ - **Actionable Guidance**: Provide practical solutions, step-by-step workflows, and troubleshooting advice.
150
+ - **Structured Reasoning**: Include numbered, logical steps to explain your reasoning.
151
 
152
+ Instructions for Responding:
153
+ 1. Start by analyzing the user's query and the retrieved context.
154
+ 2. Use step-by-step reasoning to answer the query in detail.
155
+ 3. Conclude with a concise summary of the solution.
156
+
157
+ Chat History:
158
+ {chat_history}
159
+
160
+ Retrieved Context:
161
+ {context}
 
 
 
 
 
162
 
163
+ Current Question:
164
+ {question}
165
+
166
+ Answer with detailed reasoning:
167
+ """
168
+
169
+ reasoning_prompt = ChatPromptTemplate.from_template(reasoning_prompt_template)
170
+
171
+ def create_rag_chain(chat_history: str):
172
+ chain = (
173
+ {
174
+ "context": retriever,
175
+ "question": RunnablePassthrough(),
176
+ "chat_history": lambda x: chat_history
177
+ }
178
+ | reasoning_prompt
179
+ | llm
180
+ | StrOutputParser()
181
+ )
182
+ return chain
183
+
184
+ chat_history = ChatHistory()
185
+
186
+ def process_stream(stream_queue: Queue, history: List[List[str]]) -> Generator[List[List[str]], None, None]:
187
  current_response = ""
188
 
189
+ while True:
190
+ chunk = stream_queue.get()
191
+ if chunk is None:
192
+ break
 
 
 
 
 
 
193
 
194
+ current_response += chunk
195
+ new_history = history.copy()
196
+ new_history[-1][1] = current_response
197
+ yield new_history
 
198
 
199
  async def rewrite_query(question: str, formatted_history: str) -> str:
 
200
  try:
201
  rewritten_question = await query_rewrite_chain.arun(
202
  question=question,
 
209
  logger.error(f"Error in query rewriting: {e}")
210
  return question
211
 
212
+ def ask_question_gradio(question: str, history: List[List[str]]) -> Generator[tuple, None, None]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  try:
214
  if history is None:
215
  history = []
 
217
  chat_history.add_message("user", question)
218
  formatted_history = chat_history.get_formatted_history()
219
 
220
+ # Rewrite the query
221
  rewritten_question = await rewrite_query(question, formatted_history)
222
+ rag_chain = create_rag_chain(formatted_history)
 
 
 
223
 
224
  history.append([question, ""])
 
225
 
226
+ stream_queue = Queue()
227
+
228
+ def stream_processor():
229
  try:
230
+ for chunk in rag_chain.stream(rewritten_question):
231
+ stream_queue.put(chunk)
232
+ stream_queue.put(None)
 
 
 
 
 
 
233
  except Exception as e:
234
  logger.error(f"Streaming error: {e}")
235
+ stream_queue.put(None)
236
 
237
+ Thread(target=stream_processor).start()
238
 
239
  response = ""
240
+ for updated_history in process_stream(stream_queue, history):
241
  response = updated_history[-1][1]
242
  yield "", updated_history
243
 
 
245
 
246
  except Exception as e:
247
  logger.error(f"Error during question processing: {e}")
 
248
  if not history:
249
  history = []
250
  history.append([question, "An error occurred. Please try again later."])
251
  yield "", history
252
 
253
  def clear_chat():
 
254
  chat_history.clear()
255
  return [], ""
256
 
257
  # Gradio Interface
258
  with gr.Blocks(theme='Hev832/Applio') as iface:
259
  gr.Image("Image.jpg", width=750, height=300, show_label=False, show_download_button=False)
260
+ gr.Markdown("# Mawared HR Assistant 2.7")
261
+ gr.Markdown('### Instructions')
262
+ gr.Markdown("Ask a question about MawaredHR and get a detailed answer, if you get an error try again with same prompt, its an API issue, and we are working on it.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
 
264
  chatbot = gr.Chatbot(
265
  height=750,