SamVidur commited on
Commit
7ec4f40
·
verified ·
1 Parent(s): 2705273

Update utils.py

Browse files
Files changed (1) hide show
  1. utils.py +295 -12
utils.py CHANGED
@@ -1,4 +1,264 @@
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  # utils.py
3
  import os
4
  import json
@@ -51,10 +311,16 @@ def LLMChunking():
51
  llm = ChatGroq(
52
  api_key="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",
53
  model="llama-3.3-70b-versatile",
54
- temperature=0,
55
- max_tokens=4000
 
 
 
 
 
56
  )
57
 
 
58
  # Text splitter
59
  text_splitter = RecursiveCharacterTextSplitter(
60
  separators=["\n\n", "\n", ".", " ", ""],
@@ -94,6 +360,7 @@ def initialize_rag():
94
  """
95
  vector_stores = {}
96
  qa_chains = {}
 
97
 
98
  # 1. Define Prompt Template (Modern LCEL Format)
99
  # Note: Modern chains typically look for "context" and "input" variables.
@@ -195,9 +462,10 @@ Question: {input}
195
  rag_chain = create_retrieval_chain(retriever, question_answer_chain)
196
 
197
  qa_chains[category] = rag_chain
 
198
  print(f"Initialized {category} QA chain.")
199
 
200
- return qa_chains
201
 
202
 
203
 
@@ -213,19 +481,34 @@ def classify_question_category(question):
213
  return response.content.strip()
214
 
215
  # Get RAG response using category-specific QA chain
216
- def get_rag_response(question, qa_chains):
217
- # Classify question
218
- category = classify_question_category(question)
219
 
220
- if category not in qa_chains:
221
- # Fallback to first available chain
222
- category = list(qa_chains.keys())[0]
223
 
224
- # Get response
225
- result = qa_chains[category].invoke({"input": question})
226
- return result['answer']
 
 
 
 
227
 
228
 
 
 
 
 
 
 
 
 
 
 
 
229
  # Classify user input
230
  def classify_input(user_input):
231
  prompt = f"""
 
1
 
2
+ # # utils.py
3
+ # import os
4
+ # import json
5
+ # from langchain_groq import ChatGroq
6
+ # from langchain_text_splitters import RecursiveCharacterTextSplitter
7
+ # # from langchain.schema import Document
8
+ # # from langchain.chains import RetrievalQA
9
+ # # from langchain_huggingface import HuggingFaceEmbeddings
10
+ # # from langchain_community.vectorstores import Chroma
11
+ # # from langchain.prompts import PromptTemplate
12
+
13
+ # from langchain_core.documents import Document
14
+ # from langchain_chroma import Chroma
15
+ # from langchain_huggingface import HuggingFaceEmbeddings
16
+ # from langchain_core.prompts import PromptTemplate
17
+ # # from langchain.chains import RetrievalQA
18
+ # from langchain_classic.chains import create_retrieval_chain
19
+ # from langchain_classic.chains.combine_documents import create_stuff_documents_chain
20
+ # from configure import USER_DATA_PATH, RAG_BASE_DIRECTORY, RAG_CATEGORIES
21
+ # import shutil
22
+ # from dotenv import load_dotenv
23
+ # from pymongo import MongoClient
24
+ # import certifi
25
+ # import re
26
+
27
+ # load_dotenv()
28
+
29
+
30
+ # def get_mongo_collection():
31
+ # CONNECTION_STRING = os.getenv("CONNECTION_STRING")
32
+ # DB_NAME = os.getenv("DB_NAME")
33
+ # COLLECTION_NAME = os.getenv("COLLECTION_NAME")
34
+ # try:
35
+ # # Connect with certifi to avoid SSL errors
36
+ # client = MongoClient(CONNECTION_STRING, tlsCAFile=certifi.where())
37
+ # db = client[DB_NAME]
38
+ # return db[COLLECTION_NAME]
39
+ # except Exception as e:
40
+ # print(f"Error connecting to Mongo: {e}")
41
+ # return None
42
+
43
+
44
+ # def LLMChunking():
45
+ # pass
46
+
47
+
48
+
49
+
50
+ # # LLM setup
51
+ # llm = ChatGroq(
52
+ # api_key="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",
53
+ # model="llama-3.3-70b-versatile",
54
+ # temperature=0,
55
+ # max_tokens=4000
56
+ # )
57
+
58
+ # # Text splitter
59
+ # text_splitter = RecursiveCharacterTextSplitter(
60
+ # separators=["\n\n", "\n", ".", " ", ""],
61
+ # chunk_size=500,
62
+ # chunk_overlap=100,
63
+ # length_function=len
64
+ # )
65
+ # # text_splitter = LLMChunking()
66
+
67
+ # # Embeddings
68
+ # embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
69
+ # # embeddings = None
70
+
71
+ # # Load user data
72
+ # def load_user_data():
73
+ # try:
74
+ # if os.path.exists(USER_DATA_PATH) and os.path.getsize(USER_DATA_PATH) > 0:
75
+ # with open(USER_DATA_PATH, 'r') as f:
76
+ # return json.load(f)
77
+ # except Exception:
78
+ # pass
79
+ # return {"users": {}, "user_info": {}}
80
+
81
+ # # Save user data
82
+ # def save_user_data(data):
83
+ # with open(USER_DATA_PATH, 'w') as f:
84
+ # json.dump(data, f, indent=2)
85
+
86
+ # # Initialize RAG with per-category vector stores and QA chains
87
+ # def initialize_rag():
88
+ # """
89
+ # Initialize RAG vector stores and chains using modern LangChain (LCEL).
90
+ # Args:
91
+ # llm: The initialized ChatGroq (or other) LLM object.
92
+ # embeddings: The initialized HuggingFaceEmbeddings object.
93
+ # text_splitter: The initialized RecursiveCharacterTextSplitter object.
94
+ # """
95
+ # vector_stores = {}
96
+ # qa_chains = {}
97
+
98
+ # # 1. Define Prompt Template (Modern LCEL Format)
99
+ # # Note: Modern chains typically look for "context" and "input" variables.
100
+ # base_prompt_template = """You are a {category} wellness expert. Provide helpful advice with specific actions:
101
+
102
+ # 1. Start with a brief empathetic response to the user's concern
103
+ # 2. Offer 1-3 actionable suggestions with brief explanations
104
+ # 3. End with an open-ended question to continue conversation
105
+
106
+ # Guidelines:
107
+ # - Keep responses conversational and supportive
108
+ # - Avoid clinical jargon
109
+ # - Focus on practical, implementable advice
110
+ # - Maintain hopeful and encouraging tone
111
+
112
+ # Context:
113
+ # {context}
114
+
115
+ # Question: {input}
116
+ # """
117
+
118
+ # for category in RAG_CATEGORIES:
119
+ # persist_dir = f"./chroma_db_{category}"
120
+ # vector_store = None
121
+
122
+ # # --- 2. Check/Load Existing Vector Store ---
123
+ # if os.path.exists(persist_dir):
124
+ # print(f"Found existing vector store for {category}. Attempting to load...")
125
+ # try:
126
+ # vector_store = Chroma(
127
+ # persist_directory=persist_dir,
128
+ # embedding_function=embeddings # UPDATED: 'embedding_function', not 'embedding'
129
+ # )
130
+ # vector_stores[category] = vector_store
131
+ # except Exception as e:
132
+ # print(f"Error loading existing store {persist_dir}: {e}")
133
+ # print("Will delete and attempt to re-build.")
134
+ # shutil.rmtree(persist_dir)
135
+
136
+ # # --- 3. Create Vector Store if needed ---
137
+ # if vector_store is None:
138
+ # print(f"No valid vector store for {category} found. Creating new one...")
139
+
140
+ # dir_path = os.path.join(RAG_BASE_DIRECTORY, category)
141
+ # docs = []
142
+
143
+ # if os.path.exists(dir_path):
144
+ # for filename in os.listdir(dir_path):
145
+ # if filename.endswith('.txt'):
146
+ # file_path = os.path.join(dir_path, filename)
147
+ # try:
148
+ # with open(file_path, 'r', encoding='utf-8') as f:
149
+ # text = f.read()
150
+
151
+ # chunks = text_splitter.split_text(text)
152
+ # for chunk in chunks:
153
+ # if chunk.strip():
154
+ # metadata = {
155
+ # "source": filename,
156
+ # "category": category
157
+ # }
158
+ # docs.append(Document(
159
+ # page_content=chunk.strip(),
160
+ # metadata=metadata
161
+ # ))
162
+ # except Exception as e:
163
+ # print(f"Error processing {file_path}: {e}")
164
+
165
+ # if docs:
166
+ # # UPDATED: Use 'embedding_function' instead of 'embedding'
167
+ # # UPDATED: Removed .persist() call (Auto-persists in new version)
168
+ # vector_store = Chroma.from_documents(
169
+ # documents=docs,
170
+ # embedding=embeddings,
171
+ # persist_directory=persist_dir
172
+ # )
173
+ # vector_stores[category] = vector_store
174
+ # print(f"Created new vector store for {category} with {len(docs)} documents.")
175
+ # else:
176
+ # print(f"No documents found for {category}. Skipping QA chain setup.")
177
+ # continue
178
+
179
+ # # --- 4. Create QA Chain (LCEL Style) ---
180
+ # if vector_store:
181
+ # # A. Create the Prompt
182
+ # # We inject the specific category into the template string immediately
183
+ # category_specific_template = base_prompt_template.replace("{category}", category)
184
+
185
+ # prompt = PromptTemplate(
186
+ # template=category_specific_template,
187
+ # input_variables=["context", "input"] # LCEL standard variables
188
+ # )
189
+
190
+ # # B. Create the Document Chain (LLM + Prompt)
191
+ # question_answer_chain = create_stuff_documents_chain(llm, prompt)
192
+
193
+ # # C. Create the Retrieval Chain (Retriever + Document Chain)
194
+ # retriever = vector_store.as_retriever(search_kwargs={"k": 5})
195
+ # rag_chain = create_retrieval_chain(retriever, question_answer_chain)
196
+
197
+ # qa_chains[category] = rag_chain
198
+ # print(f"Initialized {category} QA chain.")
199
+
200
+ # return qa_chains
201
+
202
+
203
+
204
+ # # Classify question to category
205
+ # def classify_question_category(question):
206
+ # prompt = f"""
207
+ # Classify this question into one category: {', '.join(RAG_CATEGORIES)}
208
+ # Question: {question}
209
+ # Respond with only the category name.
210
+ # """
211
+ # response = llm.invoke(prompt)
212
+ # print(response)
213
+ # return response.content.strip()
214
+
215
+ # # Get RAG response using category-specific QA chain
216
+ # def get_rag_response(question, qa_chains):
217
+ # # Classify question
218
+ # category = classify_question_category(question)
219
+
220
+ # if category not in qa_chains:
221
+ # # Fallback to first available chain
222
+ # category = list(qa_chains.keys())[0]
223
+
224
+ # # Get response
225
+ # result = qa_chains[category].invoke({"input": question})
226
+ # return result['answer']
227
+
228
+
229
+ # # Classify user input
230
+ # def classify_input(user_input):
231
+ # prompt = f"""
232
+ # Classify the following user input into one of these categories:
233
+ # 1. "question" - If the user is asking a factual question that could be answered with knowledge
234
+ # 2. "general" - If the user is just chatting or expressing feelings
235
+
236
+ # User Input: {user_input}
237
+
238
+ # Respond with only one word: either "question" or "general"
239
+ # """
240
+ # response = llm.invoke(prompt)
241
+ # return response.content.strip().lower()
242
+
243
+
244
+
245
+ # def parse_weird_json(text_data):
246
+ # fixed_json_string = re.sub(r'\]\s*\[', ', ', text_data.strip())
247
+
248
+ # # Step B: Load it as standard JSON
249
+ # try:
250
+ # data_list = json.loads(fixed_json_string)
251
+ # return data_list
252
+ # except json.JSONDecodeError as e:
253
+ # print(f"❌ JSON Parsing Error: {e}")
254
+ # return []
255
+
256
+
257
+
258
+
259
+
260
+
261
+
262
  # utils.py
263
  import os
264
  import json
 
311
  llm = ChatGroq(
312
  api_key="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",
313
  model="llama-3.3-70b-versatile",
314
+ temperature=0.7,
315
+ max_tokens=500,
316
+ model_kwargs={
317
+ "top_p": 0.9,
318
+ "presence_penalty": 0.5,
319
+ "frequency_penalty": 0.4
320
+ }
321
  )
322
 
323
+
324
  # Text splitter
325
  text_splitter = RecursiveCharacterTextSplitter(
326
  separators=["\n\n", "\n", ".", " ", ""],
 
360
  """
361
  vector_stores = {}
362
  qa_chains = {}
363
+ retrievers = {}
364
 
365
  # 1. Define Prompt Template (Modern LCEL Format)
366
  # Note: Modern chains typically look for "context" and "input" variables.
 
462
  rag_chain = create_retrieval_chain(retriever, question_answer_chain)
463
 
464
  qa_chains[category] = rag_chain
465
+ retrievers[category] = retriever
466
  print(f"Initialized {category} QA chain.")
467
 
468
+ return qa_chains, retrievers
469
 
470
 
471
 
 
481
  return response.content.strip()
482
 
483
  # Get RAG response using category-specific QA chain
484
+ # def get_rag_response(question, qa_chains):
485
+ # # Classify question
486
+ # category = classify_question_category(question)
487
 
488
+ # if category not in qa_chains:
489
+ # # Fallback to first available chain
490
+ # category = list(qa_chains.keys())[0]
491
 
492
+ # # Get response
493
+ # # result = qa_chains[category].invoke({"input": question})
494
+ # retriever = qa_chains[category].retriever
495
+ # docs = retriever.invoke(question)
496
+
497
+ # # return result['answer']
498
+ # return [doc.page_content for doc in docs]
499
 
500
 
501
+
502
+ def get_rag_response(question, retrievers_dict):
503
+ category = classify_question_category(question)
504
+
505
+ if category not in retrievers_dict:
506
+ category = list(retrievers_dict.keys())[0]
507
+
508
+ docs = retrievers_dict[category].invoke(question)
509
+
510
+ return "\n\n".join([doc.page_content for doc in docs])
511
+
512
  # Classify user input
513
  def classify_input(user_input):
514
  prompt = f"""