Spaces:
Running
Running
| 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() | |