Sachin21112004 commited on
Commit
f388a93
·
verified ·
1 Parent(s): 9472442

Upload 9194 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. DockerFile +20 -0
  2. api.py +53 -0
  3. cache.py +45 -0
  4. counselor.py +300 -0
  5. db.py +51 -0
  6. docs/ai ml specialist/dataset9000_5400.txt +1 -0
  7. docs/ai ml specialist/dataset9000_5401.txt +1 -0
  8. docs/ai ml specialist/dataset9000_5402.txt +1 -0
  9. docs/ai ml specialist/dataset9000_5403.txt +1 -0
  10. docs/ai ml specialist/dataset9000_5404.txt +1 -0
  11. docs/ai ml specialist/dataset9000_5405.txt +1 -0
  12. docs/ai ml specialist/dataset9000_5406.txt +1 -0
  13. docs/ai ml specialist/dataset9000_5407.txt +1 -0
  14. docs/ai ml specialist/dataset9000_5408.txt +1 -0
  15. docs/ai ml specialist/dataset9000_5409.txt +1 -0
  16. docs/ai ml specialist/dataset9000_5410.txt +1 -0
  17. docs/ai ml specialist/dataset9000_5411.txt +1 -0
  18. docs/ai ml specialist/dataset9000_5412.txt +1 -0
  19. docs/ai ml specialist/dataset9000_5413.txt +1 -0
  20. docs/ai ml specialist/dataset9000_5414.txt +1 -0
  21. docs/ai ml specialist/dataset9000_5415.txt +1 -0
  22. docs/ai ml specialist/dataset9000_5416.txt +1 -0
  23. docs/ai ml specialist/dataset9000_5417.txt +1 -0
  24. docs/ai ml specialist/dataset9000_5418.txt +1 -0
  25. docs/ai ml specialist/dataset9000_5419.txt +1 -0
  26. docs/ai ml specialist/dataset9000_5420.txt +1 -0
  27. docs/ai ml specialist/dataset9000_5421.txt +1 -0
  28. docs/ai ml specialist/dataset9000_5422.txt +1 -0
  29. docs/ai ml specialist/dataset9000_5423.txt +1 -0
  30. docs/ai ml specialist/dataset9000_5424.txt +1 -0
  31. docs/ai ml specialist/dataset9000_5425.txt +1 -0
  32. docs/ai ml specialist/dataset9000_5426.txt +1 -0
  33. docs/ai ml specialist/dataset9000_5427.txt +1 -0
  34. docs/ai ml specialist/dataset9000_5428.txt +1 -0
  35. docs/ai ml specialist/dataset9000_5429.txt +1 -0
  36. docs/ai ml specialist/dataset9000_5430.txt +1 -0
  37. docs/ai ml specialist/dataset9000_5431.txt +1 -0
  38. docs/ai ml specialist/dataset9000_5432.txt +1 -0
  39. docs/ai ml specialist/dataset9000_5433.txt +1 -0
  40. docs/ai ml specialist/dataset9000_5434.txt +1 -0
  41. docs/ai ml specialist/dataset9000_5435.txt +1 -0
  42. docs/ai ml specialist/dataset9000_5436.txt +1 -0
  43. docs/ai ml specialist/dataset9000_5437.txt +1 -0
  44. docs/ai ml specialist/dataset9000_5438.txt +1 -0
  45. docs/ai ml specialist/dataset9000_5439.txt +1 -0
  46. docs/ai ml specialist/dataset9000_5440.txt +1 -0
  47. docs/ai ml specialist/dataset9000_5441.txt +1 -0
  48. docs/ai ml specialist/dataset9000_5442.txt +1 -0
  49. docs/ai ml specialist/dataset9000_5443.txt +1 -0
  50. docs/ai ml specialist/dataset9000_5444.txt +1 -0
DockerFile ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.9-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /code
6
+
7
+ # Copy the requirements file into the container
8
+ COPY ./requirements.txt /code/requirements.txt
9
+
10
+ # Install all the Python libraries your bot needs
11
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
12
+
13
+ # Copy all your project files into the container
14
+ COPY . /code/
15
+
16
+ # Make port 8000 available to the world outside this container
17
+ EXPOSE 8000
18
+
19
+ # The command to start your bot's API server
20
+ CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"]
api.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # api.py (Corrected with CORS)
2
+
3
+ from fastapi import FastAPI
4
+ from fastapi.responses import StreamingResponse
5
+ from pydantic import BaseModel
6
+ from counselor import UltraAdvancedHybridCounselor
7
+ import logging
8
+ from fastapi.middleware.cors import CORSMiddleware # Import the CORS middleware
9
+
10
+ logging.basicConfig(
11
+ level=logging.INFO,
12
+ format='%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s',
13
+ handlers=[logging.FileHandler('logs/api.log', encoding='utf-8'), logging.StreamHandler()]
14
+ )
15
+ logger = logging.getLogger(__name__)
16
+
17
+ app = FastAPI()
18
+
19
+ # --- START OF CORRECTION ---
20
+ # This block allows your React frontend (e.g., running on http://localhost:3000)
21
+ # to make requests to your Python backend without being blocked by browser security.
22
+ origins = [
23
+ "http://localhost:3000",
24
+ "http://localhost:3001",
25
+ ]
26
+
27
+ app.add_middleware(
28
+ CORSMiddleware,
29
+ allow_origins=origins,
30
+ allow_credentials=True,
31
+ allow_methods=["*"], # Allows all methods (GET, POST, etc.)
32
+ allow_headers=["*"], # Allows all headers
33
+ )
34
+ # --- END OF CORRECTION ---
35
+
36
+ counselor = UltraAdvancedHybridCounselor()
37
+
38
+ class CounselRequest(BaseModel):
39
+ query: str
40
+ session_id: str
41
+
42
+ @app.post("/counsel")
43
+ async def counsel(request: CounselRequest):
44
+ async def stream_gen():
45
+ try:
46
+ # Correctly iterate over the async generator
47
+ async for chunk in counselor.get_comprehensive_answer(request.query, request.session_id):
48
+ yield chunk.encode('utf-8')
49
+ except Exception as e:
50
+ logger.error(f"Streaming error: {e}")
51
+ yield "An error occurred during streaming.".encode('utf-8')
52
+
53
+ return StreamingResponse(stream_gen(), media_type="text/plain")
cache.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import redis
2
+ from dotenv import load_dotenv
3
+ import os
4
+ import pickle
5
+ import logging
6
+
7
+ logging.basicConfig(
8
+ level=logging.INFO,
9
+ format='%(asctime)s - %(levelname)s - %(message)s',
10
+ handlers=[logging.FileHandler('logs/cache.log', encoding='utf-8'), logging.StreamHandler()]
11
+ )
12
+ logger = logging.getLogger(__name__)
13
+
14
+ load_dotenv()
15
+
16
+ class RedisCache:
17
+ def __init__(self):
18
+ try:
19
+ self.client = redis.Redis(
20
+ host=os.getenv('REDIS_HOST', 'localhost'),
21
+ port=int(os.getenv('REDIS_PORT', 6379)),
22
+ db=0,
23
+ decode_responses=False
24
+ )
25
+ self.client.ping()
26
+ logger.info("Connected to Redis")
27
+ except Exception as e:
28
+ logger.error(f"Failed to connect to Redis: {e}")
29
+ raise
30
+
31
+ def get(self, key):
32
+ try:
33
+ value = self.client.get(key)
34
+ if value:
35
+ return pickle.loads(value)
36
+ return None
37
+ except Exception as e:
38
+ logger.error(f"Error retrieving from cache: {e}")
39
+ return None
40
+
41
+ def set(self, key, value, ttl=7200):
42
+ try:
43
+ self.client.setex(key, ttl, pickle.dumps(value))
44
+ except Exception as e:
45
+ logger.error(f"Error setting cache: {e}")
counselor.py ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import hashlib
3
+ import logging
4
+ from typing import AsyncGenerator, Dict, Any
5
+ from transformers import DistilBertTokenizer, DistilBertForSequenceClassification
6
+ import torch
7
+ from langchain_google_genai import ChatGoogleGenerativeAI
8
+ from langchain.prompts import PromptTemplate
9
+ from langchain.chains import LLMChain
10
+ from rag import RAGComponent
11
+ from db import SessionDB
12
+ from cache import RedisCache
13
+ import joblib
14
+ from pathlib import Path
15
+ from dotenv import load_dotenv
16
+ import os
17
+
18
+ load_dotenv()
19
+
20
+ logging.basicConfig(
21
+ level=logging.INFO,
22
+ format='%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s',
23
+ handlers=[logging.FileHandler('logs/counselor.log', encoding='utf-8'), logging.StreamHandler()]
24
+ )
25
+ logger = logging.getLogger(__name__)
26
+
27
+ class UltraAdvancedHybridCounselor:
28
+ def __init__(self):
29
+ self.model_path = "./models"
30
+ self.label_encoder_path = "./models/label_encoder.pkl"
31
+ try:
32
+ self.tokenizer = DistilBertTokenizer.from_pretrained(self.model_path)
33
+ self.model = DistilBertForSequenceClassification.from_pretrained(self.model_path)
34
+ self.label_encoder = joblib.load(self.label_encoder_path) if Path(self.label_encoder_path).exists() else None
35
+ except Exception as e:
36
+ logger.error(f"Error loading model or tokenizer: {e}")
37
+ raise
38
+ self.rag = RAGComponent()
39
+ self.db = SessionDB()
40
+ # Check if Redis should be used
41
+ self.use_redis = os.getenv("USE_REDIS", "false").lower() == "true"
42
+ if self.use_redis:
43
+ try:
44
+ self.cache = RedisCache()
45
+ except Exception as e:
46
+ logger.error(f"Failed to initialize RedisCache: {e}. Falling back to no caching.")
47
+ self.cache = None
48
+ else:
49
+ logger.info("Redis caching disabled (USE_REDIS=false).")
50
+ self.cache = None
51
+ self.llm = ChatGoogleGenerativeAI(
52
+ model="gemini-1.5-pro-latest",
53
+ temperature=0.1,
54
+ max_tokens=4096,
55
+ google_api_key=os.getenv("GOOGLE_API_KEY")
56
+ )
57
+ self._setup_prompts()
58
+
59
+ def _setup_prompts(self):
60
+ self.intent_template = """
61
+ You are an expert career intent classifier. Classify the user's query into one of these categories:
62
+ - career_recommendation: Questions about suggested careers based on skills/interests
63
+ - resume_advice: Advice on resumes, CVs, cover letters
64
+ - interview_prep: Preparation for interviews, questions, behavioral advice
65
+ - salary_info: Salary expectations, negotiation, market rates
66
+ - career_transition: Switching careers, upskilling, education paths
67
+ - general_question: Any other career-related query
68
+
69
+ Query: {query}
70
+
71
+ Respond only with the category name.
72
+ """
73
+
74
+ self.enhancer_template = """
75
+ You are an elite career counselor. An advanced ML model recommends '{recommendation}' with {confidence:.1%} confidence.
76
+ Similar profiles: {rag_context}
77
+ Conversation history: {history}
78
+
79
+ Provide a comprehensive response including:
80
+ 1. **Role Overview**: Daily responsibilities and key tasks
81
+ 2. **Fit Analysis**: How it aligns with the user's profile
82
+ 3. **Skills & Education**: Essential skills, degrees, certifications
83
+ 4. **Career Ladder**: Progression from entry to executive levels
84
+ 5. **Market Insights**: Job demand, salary ranges (2025), growth projections
85
+ 6. **Action Plan**: 7 specific, timed steps to pursue this career
86
+ 7. **Alternatives**: 4 related careers with brief pros/cons
87
+
88
+ Tone: Encouraging, professional, empowering. Structure with headers.
89
+
90
+ User Query: {user_query}
91
+ """
92
+
93
+ self.resume_template = """
94
+ As a top resume expert, provide detailed advice for the user's query: {question}
95
+ Conversation history: {history}
96
+
97
+ Include:
98
+ - Structure recommendations
99
+ - Key sections and content tips
100
+ - Tailoring for ATS
101
+ - Common mistakes to avoid
102
+ - Examples specific to career fields
103
+
104
+ Use bullet points for clarity.
105
+ """
106
+
107
+ self.interview_template = """
108
+ Expert interview coach response for: {question}
109
+ Conversation history: {history}
110
+
111
+ Cover:
112
+ - Common questions and sample answers
113
+ - Behavioral STAR method examples
114
+ - Body language and virtual tips
115
+ - Follow-up strategies
116
+ - Industry-specific advice
117
+
118
+ Structured and actionable.
119
+ """
120
+
121
+ self.salary_template = """
122
+ Career salary specialist: Answer {question}
123
+ Conversation history: {history}
124
+
125
+ Provide:
126
+ - Current (2025) ranges by experience/level/location
127
+ - Negotiation tactics
128
+ - Factors influencing pay (skills, certs)
129
+ - Benefits and perks overview
130
+ - Sources for up-to-date data
131
+
132
+ Use tables for ranges.
133
+ """
134
+
135
+ self.transition_template = """
136
+ Career transition advisor: Guide on {question}
137
+ Conversation history: {history}
138
+
139
+ Include:
140
+ - Assessment of current vs target skills
141
+ - Upskilling resources (courses, books)
142
+ - Networking strategies
143
+ - Timeline estimates
144
+ - Success stories/examples
145
+
146
+ Motivational and step-by-step.
147
+ """
148
+
149
+ self.general_template = """
150
+ Comprehensive career advisor response for: {question}
151
+ Conversation history: {history}
152
+
153
+ Ensure depth, practicality, and relevance to career development.
154
+ """
155
+
156
+ self.intent_chain = LLMChain(llm=self.llm, prompt=PromptTemplate.from_template(self.intent_template))
157
+ self.enhancer_chain = LLMChain(llm=self.llm, prompt=PromptTemplate.from_template(self.enhancer_template))
158
+ self.resume_chain = LLMChain(llm=self.llm, prompt=PromptTemplate.from_template(self.resume_template))
159
+ self.interview_chain = LLMChain(llm=self.llm, prompt=PromptTemplate.from_template(self.interview_template))
160
+ self.salary_chain = LLMChain(llm=self.llm, prompt=PromptTemplate.from_template(self.salary_template))
161
+ self.transition_chain = LLMChain(llm=self.llm, prompt=PromptTemplate.from_template(self.transition_template))
162
+ self.general_chain = LLMChain(llm=self.llm, prompt=PromptTemplate.from_template(self.general_template))
163
+
164
+ async def classify_intent(self, query: str) -> str:
165
+ if not self.cache:
166
+ try:
167
+ response = await self.intent_chain.ainvoke({"query": query})
168
+ intent = response['text'].strip().lower()
169
+ return intent
170
+ except Exception as e:
171
+ logger.error(f"Intent classification error: {e}")
172
+ return "general_question"
173
+
174
+ cache_key = f"intent_{hashlib.sha256(query.encode()).hexdigest()}"
175
+ cached = self.cache.get(cache_key)
176
+ if cached:
177
+ return cached
178
+
179
+ try:
180
+ response = await self.intent_chain.ainvoke({"query": query})
181
+ intent = response['text'].strip().lower()
182
+ self.cache.set(cache_key, intent)
183
+ return intent
184
+ except Exception as e:
185
+ logger.error(f"Intent classification error: {e}")
186
+ return "general_question"
187
+
188
+ async def predict_career(self, query: str) -> Dict[str, Any]:
189
+ if not self.cache:
190
+ try:
191
+ inputs = self.tokenizer(query.lower(), return_tensors="pt", padding=True, truncation=True, max_length=128)
192
+ with torch.no_grad():
193
+ outputs = self.model(**inputs)
194
+ probs = torch.softmax(outputs.logits, dim=1)
195
+ pred_label = probs.argmax().item()
196
+ confidence = probs.max().item()
197
+ if self.label_encoder is None:
198
+ raise ValueError("Label encoder not loaded")
199
+ career = self.label_encoder.inverse_transform([pred_label])[0]
200
+ return {"recommendation": career, "confidence": confidence}
201
+ except Exception as e:
202
+ logger.error(f"Prediction error: {e}")
203
+ return {"recommendation": None, "confidence": 0.0, "error": str(e)}
204
+
205
+ cache_key = f"predict_{hashlib.sha256(query.encode()).hexdigest()}"
206
+ cached = self.cache.get(cache_key)
207
+ if cached:
208
+ return cached
209
+
210
+ try:
211
+ inputs = self.tokenizer(query.lower(), return_tensors="pt", padding=True, truncation=True, max_length=128)
212
+ with torch.no_grad():
213
+ outputs = self.model(**inputs)
214
+ probs = torch.softmax(outputs.logits, dim=1)
215
+ pred_label = probs.argmax().item()
216
+ confidence = probs.max().item()
217
+ if self.label_encoder is None:
218
+ raise ValueError("Label encoder not loaded")
219
+ career = self.label_encoder.inverse_transform([pred_label])[0]
220
+ result = {"recommendation": career, "confidence": confidence}
221
+ self.cache.set(cache_key, result)
222
+ return result
223
+ except Exception as e:
224
+ logger.error(f"Prediction error: {e}")
225
+ return {"recommendation": None, "confidence": 0.0, "error": str(e)}
226
+
227
+ async def get_comprehensive_answer(self, user_query: str, session_id: str) -> AsyncGenerator[str, None]:
228
+ history = self.db.get_history(session_id)
229
+ history_str = "\n".join([f"User: {h[0]}\nBot: {h[1]}" for h in history]) if history else ""
230
+ full_response = ""
231
+
232
+ try:
233
+ intent = await self.classify_intent(user_query)
234
+ logger.info(f"Detected intent: {intent}")
235
+
236
+ if intent == "career_recommendation":
237
+ prediction = await self.predict_career(user_query)
238
+
239
+ # --- START OF CHANGES ---
240
+
241
+ # 1. Lowered confidence threshold from 0.95 to 0.75
242
+ if prediction.get('recommendation') and prediction.get('confidence', 0) >= 0.75:
243
+ logger.info(f"High confidence prediction: {prediction['recommendation']} ({prediction['confidence']:.2f})")
244
+ similar = self.rag.retrieve_similar(user_query)
245
+ rag_context = "\n".join([f"Profile: {s['profile'][:100]}... -> {s['career']}" for s in similar])
246
+ async for chunk in self.enhancer_chain.astream({
247
+ "recommendation": prediction['recommendation'],
248
+ "confidence": prediction['confidence'],
249
+ "rag_context": rag_context,
250
+ "history": history_str,
251
+ "user_query": user_query
252
+ }):
253
+ full_response += chunk['text']
254
+ yield chunk['text']
255
+ else:
256
+ # 2. Added a smart fallback for low-confidence predictions
257
+ confidence_score = prediction.get('confidence', 0)
258
+ logger.warning(f"Low confidence ({confidence_score:.2f}). Falling back to general chain.")
259
+
260
+ # Add a prefix to the response to manage user expectations
261
+ fallback_prefix = "While I couldn't determine a single best career with high confidence, here is some general guidance based on your profile and interests:\n\n"
262
+ yield fallback_prefix
263
+ full_response += fallback_prefix
264
+
265
+ async for chunk in self.general_chain.astream({"question": user_query, "history": history_str}):
266
+ full_response += chunk['text']
267
+ yield chunk['text']
268
+
269
+ # --- END OF CHANGES ---
270
+
271
+ elif intent == "resume_advice":
272
+ async for chunk in self.resume_chain.astream({"question": user_query, "history": history_str}):
273
+ full_response += chunk['text']
274
+ yield chunk['text']
275
+ elif intent == "interview_prep":
276
+ async for chunk in self.interview_chain.astream({"question": user_query, "history": history_str}):
277
+ full_response += chunk['text']
278
+ yield chunk['text']
279
+ elif intent == "salary_info":
280
+ async for chunk in self.salary_chain.astream({"question": user_query, "history": history_str}):
281
+ full_response += chunk['text']
282
+ yield chunk['text']
283
+ elif intent == "career_transition":
284
+ async for chunk in self.transition_chain.astream({"question": user_query, "history": history_str}):
285
+ full_response += chunk['text']
286
+ yield chunk['text']
287
+ else: # Handles general_question intent
288
+ async for chunk in self.general_chain.astream({"question": user_query, "history": history_str}):
289
+ full_response += chunk['text']
290
+ yield chunk['text']
291
+
292
+ history.append([user_query, full_response])
293
+ self.db.save_history(session_id, history)
294
+
295
+ except Exception as e:
296
+ logger.error(f"Processing error: {e}")
297
+ error_msg = "An error occurred. Please try again."
298
+ history.append([user_query, error_msg])
299
+ self.db.save_history(session_id, history)
300
+ yield error_msg
db.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # db.py (Corrected)
2
+ import sqlite3
3
+ import logging
4
+ import json # Import json
5
+
6
+ logging.basicConfig(
7
+ level=logging.INFO,
8
+ format='%(asctime)s - %(levelname)s - %(message)s',
9
+ handlers=[logging.FileHandler('logs/db.log', encoding='utf-8'), logging.StreamHandler()]
10
+ )
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class SessionDB:
14
+ def __init__(self, db_path="sessions.db"):
15
+ self.conn = sqlite3.connect(db_path, check_same_thread=False)
16
+ self.cursor = self.conn.cursor()
17
+ self.create_table()
18
+
19
+ def create_table(self):
20
+ try:
21
+ self.cursor.execute('''
22
+ CREATE TABLE IF NOT EXISTS sessions (
23
+ session_id TEXT PRIMARY KEY,
24
+ history TEXT
25
+ )
26
+ ''')
27
+ self.conn.commit()
28
+ except Exception as e:
29
+ logger.error(f"Error creating sessions table: {e}")
30
+
31
+ def get_history(self, session_id, max_turns=4):
32
+ try:
33
+ self.cursor.execute("SELECT history FROM sessions WHERE session_id=?", (session_id,))
34
+ result = self.cursor.fetchone()
35
+ if result:
36
+ # Use json.loads for safety instead of eval()
37
+ history = json.loads(result[0])
38
+ return history[-max_turns:]
39
+ return []
40
+ except Exception as e:
41
+ logger.error(f"Error retrieving history for session {session_id}: {e}")
42
+ return []
43
+
44
+ def save_history(self, session_id, history):
45
+ try:
46
+ # Use json.dumps for safety instead of str()
47
+ history_str = json.dumps(history)
48
+ self.cursor.execute("INSERT OR REPLACE INTO sessions (session_id, history) VALUES (?, ?)", (session_id, history_str))
49
+ self.conn.commit()
50
+ except Exception as e:
51
+ logger.error(f"Error saving history for session {session_id}: {e}")
docs/ai ml specialist/dataset9000_5400.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional not interested not interested not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5401.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional poor not interested not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5402.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional beginner not interested not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5403.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional average not interested not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5404.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional intermediate not interested not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5405.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional excellent not interested not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5406.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poor poor poor poor poor poor poor poor poor poor professional not interested poor poor poor poor poor
docs/ai ml specialist/dataset9000_5407.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poor poor poor poor poor poor poor poor poor poor professional poor poor poor poor poor poor
docs/ai ml specialist/dataset9000_5408.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poor poor poor poor poor poor poor poor poor poor professional beginner poor poor poor poor poor
docs/ai ml specialist/dataset9000_5409.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poor poor poor poor poor poor poor poor poor poor professional average poor poor poor poor poor
docs/ai ml specialist/dataset9000_5410.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poor poor poor poor poor poor poor poor poor poor professional intermediate poor poor poor poor poor
docs/ai ml specialist/dataset9000_5411.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poor poor poor poor poor poor poor poor poor poor professional excellent poor poor poor poor poor
docs/ai ml specialist/dataset9000_5412.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ beginner beginner beginner beginner beginner beginner beginner beginner beginner beginner professional not interested beginner beginner beginner beginner beginner
docs/ai ml specialist/dataset9000_5413.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ beginner beginner beginner beginner beginner beginner beginner beginner beginner beginner professional poor beginner beginner beginner beginner beginner
docs/ai ml specialist/dataset9000_5414.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ beginner beginner beginner beginner beginner beginner beginner beginner beginner beginner professional beginner beginner beginner beginner beginner beginner
docs/ai ml specialist/dataset9000_5415.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ beginner beginner beginner beginner beginner beginner beginner beginner beginner beginner professional average beginner beginner beginner beginner beginner
docs/ai ml specialist/dataset9000_5416.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ beginner beginner beginner beginner beginner beginner beginner beginner beginner beginner professional intermediate beginner beginner beginner beginner beginner
docs/ai ml specialist/dataset9000_5417.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ beginner beginner beginner beginner beginner beginner beginner beginner beginner beginner professional excellent beginner beginner beginner beginner beginner
docs/ai ml specialist/dataset9000_5418.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ average average average average average average average average average average professional not interested average average average average average
docs/ai ml specialist/dataset9000_5419.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ average average average average average average average average average average professional poor average average average average average
docs/ai ml specialist/dataset9000_5420.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ average average average average average average average average average average professional beginner average average average average average
docs/ai ml specialist/dataset9000_5421.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ average average average average average average average average average average professional average average average average average average
docs/ai ml specialist/dataset9000_5422.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ average average average average average average average average average average professional intermediate average average average average average
docs/ai ml specialist/dataset9000_5423.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ average average average average average average average average average average professional excellent average average average average average
docs/ai ml specialist/dataset9000_5424.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate professional not interested intermediate intermediate intermediate intermediate intermediate
docs/ai ml specialist/dataset9000_5425.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate professional poor intermediate intermediate intermediate intermediate intermediate
docs/ai ml specialist/dataset9000_5426.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate professional beginner intermediate intermediate intermediate intermediate intermediate
docs/ai ml specialist/dataset9000_5427.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate professional average intermediate intermediate intermediate intermediate intermediate
docs/ai ml specialist/dataset9000_5428.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate professional intermediate intermediate intermediate intermediate intermediate intermediate
docs/ai ml specialist/dataset9000_5429.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate intermediate professional excellent intermediate intermediate intermediate intermediate intermediate
docs/ai ml specialist/dataset9000_5430.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ excellent excellent excellent excellent excellent excellent excellent excellent excellent excellent professional not interested excellent excellent excellent excellent excellent
docs/ai ml specialist/dataset9000_5431.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ excellent excellent excellent excellent excellent excellent excellent excellent excellent excellent professional poor excellent excellent excellent excellent excellent
docs/ai ml specialist/dataset9000_5432.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ excellent excellent excellent excellent excellent excellent excellent excellent excellent excellent professional beginner excellent excellent excellent excellent excellent
docs/ai ml specialist/dataset9000_5433.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ excellent excellent excellent excellent excellent excellent excellent excellent excellent excellent professional average excellent excellent excellent excellent excellent
docs/ai ml specialist/dataset9000_5434.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ excellent excellent excellent excellent excellent excellent excellent excellent excellent excellent professional intermediate excellent excellent excellent excellent excellent
docs/ai ml specialist/dataset9000_5435.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ excellent excellent excellent excellent excellent excellent excellent excellent excellent excellent professional excellent excellent excellent excellent excellent excellent
docs/ai ml specialist/dataset9000_5436.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional not interested not interested not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5437.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional not interested poor not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5438.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional not interested beginner not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5439.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional not interested average not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5440.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional not interested intermediate not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5441.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ not interested not interested not interested not interested not interested not interested not interested not interested not interested not interested professional not interested excellent not interested not interested not interested not interested
docs/ai ml specialist/dataset9000_5442.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poor poor poor poor poor poor poor poor poor poor professional poor not interested poor poor poor poor
docs/ai ml specialist/dataset9000_5443.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poor poor poor poor poor poor poor poor poor poor professional poor poor poor poor poor poor
docs/ai ml specialist/dataset9000_5444.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poor poor poor poor poor poor poor poor poor poor professional poor beginner poor poor poor poor