import requests import sys import transformers import sentence_transformers import os from dotenv import load_dotenv load_dotenv() # Suppress warnings def warn(*args, **kwargs): pass import warnings warnings.warn = warn warnings.filterwarnings("ignore") # Document loading from langchain_community.document_loaders import PyMuPDFLoader # Text splitting from langchain_text_splitters import RecursiveCharacterTextSplitter # Vector store from langchain_community.vectorstores import Chroma # Embeddings from langchain_huggingface import HuggingFaceEmbeddings #loader = PyMuPDFLoader("FAQ_NEW.pdf") PDF_NAME = "FAQ_NEW.pdf" PDF_URL = "https://huggingface.co/datasets/vivekmehta27/btech-rag-data/resolve/main/FAQ_NEW.pdf" if not os.path.exists(PDF_NAME): print("Downloading PDF...") response = requests.get(PDF_URL) response.raise_for_status() with open(PDF_NAME, "wb") as f: f.write(response.content) print("Download completed.") loader = PyMuPDFLoader(PDF_NAME) documents = loader.load() print(documents[0].page_content) text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=100 ) texts = text_splitter.split_documents(documents) print("Number of chunks:", len(texts)) #print("\nFirst chunk:\n") #print(texts[0].page_content[:500]) for i, chunk in enumerate(texts[:5]): print(f"\n{'='*50}") print(f"CHUNK {i+1}") print(f"{'='*50}") print(chunk.page_content) embeddings = HuggingFaceEmbeddings( model_name="sentence-transformers/all-MiniLM-L6-v2" ) docsearch = Chroma.from_documents( documents=texts, embedding=embeddings ) print("Document ingestion completed.") print("Number of chunks stored:", len(texts)) """## LLM model construction """ from langchain_nvidia_ai_endpoints import ChatNVIDIA print("API Key:", os.getenv("NVIDIA_API_KEY")) llm = ChatNVIDIA( model="meta/llama-3.1-8b-instruct", api_key=os.getenv("NVIDIA_API_KEY"), temperature=0.2, top_p=0.7, max_tokens=1024, ) # User's question query = " if a student has backlog in one VAC course like design thinking here for example, then by choosing some other VAC course in this list will his /her requirement of 3 vac courses still be considered as in can one vac course replace the other then?" # Retrieve the top 3 most relevant chunks from the vector database docs = docsearch.similarity_search(query, k=3) # Display the retrieved chunks for i, doc in enumerate(docs): # Print chunk number print(f"\n{'='*60}") print(f"RETRIEVED CHUNK {i+1}") print(f"{'='*60}") # Print chunk content print(doc.page_content) # Print metadata (source document information) print("\nMetadata:", doc.metadata) """## The next step is Augmentation (constructing the prompt) and then Generation (sending it to the LLM). ## Build Context from Retrieved Chunks """ # Combine the retrieved chunks into a single context context = "\n\n".join([doc.page_content for doc in docs]) print("Context Length:", len(context)) print("\nContext Sent to LLM:\n") print(context) """# Create the Prompt""" # Construct the RAG prompt prompt = f""" You are a helpful assistant. Answer the question using only the provided context. Context: {context} Question: {query} Answer: """ print(prompt) """# Invoke the LLM""" # Generate answer using the LLM response = llm.invoke(prompt) print(response.content) """### RAG summary ### Stage 1: Retrieval docs = docsearch.similarity_search(query, k=3) ### Stage 2: Augmentation context = "\n\n".join([doc.page_content for doc in docs]) ### Stage 3: Generation prompt = f''' Answer the question using only the context below. Context: {context} Question: {query} Answer: ''' response = llm.invoke(prompt) print(response.content) # chatbot with memory """ class RAGChatbot: """ A simple RAG chatbot with conversation memory. """ def __init__(self, llm, vector_db, k=3): """ Initialize the chatbot. Parameters: llm : Language model object vector_db : Chroma vector database k : Number of chunks to retrieve """ self.llm = llm self.vector_db = vector_db self.k = k self.chat_history = [] def ask(self, query): """ Ask a question to the chatbot. """ # Retrieve relevant chunks docs = self.vector_db.similarity_search( query, k=self.k ) # Combine retrieved chunks into a context context = "\n\n".join( [doc.page_content for doc in docs] ) # Convert chat history into text history_text = "\n".join( [ f"User: {q}\nAssistant: {a}" for q, a in self.chat_history ] ) # Create RAG prompt prompt = f""" You are a helpful assistant. Previous Conversation: {history_text} Context: {context} Current Question: {query} Answer: """ # Generate response response = self.llm.invoke(prompt) answer = response.content # Update memory self.chat_history.append( (query, answer) ) return answer def show_history(self): """ Display conversation history. """ for i, (q, a) in enumerate(self.chat_history, start=1): print(f"\nConversation {i}") print(f"User : {q}") print(f"Assistant : {a}") def clear_history(self): """ Clear chatbot memory. """ self.chat_history = [] print("Conversation history cleared.") chatbot = RAGChatbot( llm=llm, vector_db=docsearch, k=3 ) chatbot.ask( " if that student has backlog in one VAC course like design thinking here for example, then by choosing some other VAC course in this list will his /her requirement of 3 vac courses still be considered as in can one vac course replace the other then?" ) chatbot.ask( "Can employees use personal devices?" ) chatbot.ask( "Summarize the policy in three points." ) """# Creating a GUI with gradio""" # Commented out IPython magic to ensure Python compatibility. # %%capture # !{sys.executable} -m pip install -U gradio import gradio as gr # Function that Gradio will call def chat_with_rag(message, history): response = chatbot.ask(message) return response # Create interface demo = gr.ChatInterface( fn=chat_with_rag, title="Btech Policy RAG Chatbot", description="Ask questions about Btech regulations." ) if __name__ == "__main__": demo.launch()