|
3 | 3 | from langchain_text_splitters import RecursiveCharacterTextSplitter |
4 | 4 | from langchain_community.vectorstores import Chroma |
5 | 5 | from langchain_ollama import OllamaEmbeddings |
| 6 | +from pymongo import MongoClient |
| 7 | +import datetime |
6 | 8 | import ollama |
7 | 9 |
|
| 10 | +# MongoDB Setup |
| 11 | +print("[INFO] Connecting to MongoDB...") |
| 12 | +try: |
| 13 | + # Connecting to default local MongoDB Port |
| 14 | + mongo_client = MongoClient("mongodb://localhost:27017/", serverSelectionTimeoutMS=2000) |
| 15 | + |
| 16 | + # Forcing a connection test |
| 17 | + mongo_client.server_info() |
| 18 | + db = mongo_client["hr_assistant"] |
| 19 | + chat_collection = db["chat_history"] |
| 20 | + print("[OK] Connected to MongoDB!") |
| 21 | +except Exception as e: |
| 22 | + print("[ERROR] Could not connect to MongoDB. Is the server running?") |
| 23 | + exit(1) |
| 24 | + |
| 25 | +# Dynamic Session ID for handling users and their past questions |
| 26 | +print("\nWelcome to HR Buddy") |
| 27 | +SESSION_ID = input("Please enter your name to login: ").strip() |
| 28 | + |
| 29 | +# Fallback support as a guest session |
| 30 | +if not SESSION_ID: |
| 31 | + SESSION_ID = "guest_user" |
| 32 | + print("[INFO] No name provided. Logging in as 'guest_user'.") |
| 33 | +else: |
| 34 | + print(f"[INFO] Hello, {SESSION_ID}! Fetching your records...") |
| 35 | + |
| 36 | + |
8 | 37 | # Load and Chunk the Data |
9 | 38 | print("[INFO] Reading HR Policy PDF...") |
10 | 39 | loader = PyMuPDFLoader("rag_source/nasscom-hr-manual-2016.pdf") |
|
15 | 44 | chunks = text_splitter.split_documents(pages) |
16 | 45 |
|
17 | 46 | # Embed and Store in Vector DB |
18 | | -print("[INFO] Embedding text and building Chroma database...") |
| 47 | +print(f"[INFO] Chunking complete. Found {len(chunks)} text chunks.") |
| 48 | +print("[INFO] Sending chunks to Ollama to create embeddings...") |
19 | 49 | # fast, local nomic model to turn text into math |
20 | 50 | embeddings = OllamaEmbeddings(model="nomic-embed-text") |
21 | 51 | vectorstore = Chroma.from_documents(documents=chunks, embedding=embeddings) |
|
30 | 60 | while True: |
31 | 61 | user_input = input("\n:> ") |
32 | 62 |
|
33 | | - # Semantic Search: Find the relevant policy paragraphs |
| 63 | + # Get last 10 messages from the user |
| 64 | + past_messages_cursor = chat_collection.find({"session_id": SESSION_ID}).sort("timestamp", -1).limit(10) |
| 65 | + |
| 66 | + # Convert cursor to list and reverse for reading it from start to end |
| 67 | + past_messages = list(past_messages_cursor)[::-1] |
| 68 | + history_text = "\n".join([f"{msg['role']}: {msg['content']}" for msg in past_messages]) |
| 69 | + |
| 70 | + # Semantic Search: Find the relevant policy paragraphs from the RAG source |
34 | 71 | docs = retriever.invoke(user_input) |
35 | 72 | context_block = "\n\n".join([doc.page_content for doc in docs]) |
36 | 73 |
|
|
41 | 78 | |
42 | 79 | If the Context does not contain the exact answer, simply reply: "I cannot find the answer to that in the current policy." |
43 | 80 | |
44 | | - Context: |
| 81 | + --- PAST CONVERSATION MEMORY --- |
| 82 | + {history_text} |
| 83 | + |
| 84 | + --- CURRENT HR CONTEXT --- |
45 | 85 | {context_block} |
46 | 86 | |
| 87 | + --- CURRENT QUESTION --- |
47 | 88 | Question: {user_input} |
48 | 89 | Answer:""" |
49 | 90 |
|
|
52 | 93 | {'role': 'user', 'content': rag_prompt} |
53 | 94 | ]) |
54 | 95 |
|
55 | | - print(f"\nAI: {response['message']['content']}") |
| 96 | + ai_answer = response['message']['content'] |
| 97 | + print(f"\nAI: {ai_answer}") |
| 98 | + |
| 99 | + chat_collection.insert_many([ |
| 100 | + {"session_id": SESSION_ID, "role": "User", "content": user_input, "timestamp": datetime.datetime.now(datetime.timezone.utc)}, |
| 101 | + {"session_id": SESSION_ID, "role": "AI", "content": ai_answer, "timestamp": datetime.datetime.now(datetime.timezone.utc)} |
| 102 | + ]) |
56 | 103 |
|
57 | 104 | except KeyboardInterrupt: |
58 | 105 | print("\n\n[INFO] Closing Chat.") |
|
0 commit comments