srinit62's picture
Update app.py
0c0b010 verified
Raw History Blame Contribute Delete
6.17 kB
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_chroma import Chroma
# Importing RunnableLambda for wrapping functions as runnable components.
from langchain_core.runnables import RunnableLambda
from langchain_core.prompts import PromptTemplate # To format prompts
from langchain_core.output_parsers import StrOutputParser # to transform the output of an LLM into a more usable format
from langchain.schema.runnable import RunnableParallel, RunnablePassthrough
# importing HuggingFace model abstraction class from langchain
from langchain_huggingface import HuggingFaceEndpoint
import torch
import gradio
import re
# Initializing a Hugging Face endpoint for text generation using a specific model.
llm = HuggingFaceEndpoint(
repo_id="HuggingFaceH4/zephyr-7b-beta", # Specifies the model to be used (Zephyr-7B Beta), available on Hugging Face.
task="text-generation", # Defines the task type as text generation (commonly used for chatbots, summarization, etc.).
max_new_tokens=512, # Limits the maximum number of new tokens the model can generate in a response.
top_k=30, # Controls the diversity of the generated text by restricting the number of top probable tokens considered at each step.
temperature=0.1, # A low temperature value makes the model’s output more deterministic and focused.
repetition_penalty=1.03, # Slightly penalizes repeated tokens to reduce redundancy in responses.
)
# Initializing the Hugging Face embedding model.
embedding = HuggingFaceEmbeddings(
model_name="mixedbread-ai/mxbai-embed-large-v1", # Using a pre-trained embedding model for text vectorization.
model_kwargs={'device': "cuda" if torch.cuda.is_available() else "cpu"}, # Configuring the model to use GPU if available.
encode_kwargs={'normalize_embeddings': False} # Disabling normalization to preserve the original embedding scale.
)
# Creating a Chroma vector database instance.
vectordb = Chroma(
persist_directory= './chroma/', #'RAG_Implementation/chroma/', # Setting the directory where embeddings will be stored.
embedding_function=embedding # Specifying the embedding function to convert text into vector representations.
)
# Function to retrieve relevant document chunks based on a given question.
def get_context_info(question):
# Creating a retriever using the Chroma vector database with Maximum Marginal Relevance (MMR).
# `search_type="mmr"` ensures diversity in retrieved results.
# `fetch_k=5` first fetches the top 5 most relevant chunks.
# `k=3` selects the 3 most diverse and relevant chunks from the 5 fetched.
retriever = vectordb.as_retriever(search_type="mmr", search_kwargs={"k": 3, "fetch_k": 5})
# Retrieving the document chunks using the retriever.
docs = retriever.invoke(question)
# Returning the retrieved document chunks.
return docs
# Creating a retrieval pipeline using RunnableParallel.
retrieval = RunnableParallel(
{
# Retrieving relevant document chunks based on the input question.
# RunnableLambda ensures that `get_context_info` runs dynamically when called.
"context": RunnableLambda(lambda x: get_context_info(x["question"])),
# Simply passing the question as is.
"question": RunnableLambda(lambda x: x["question"])
}
)
# Defining a prompt template for answering questions based on retrieved context.
template = """Use the following pieces of context to answer the question at the end.
If you don't know the answer, that is if the answer is not in the context, then just say that you don't know, don't try to make up an answer.
Always say "thanks for asking!" at the end of the answer.
{context}
Question: {question}
Helpful Answer:"""
# Creating a PromptTemplate object using the defined template.
# The template takes two input variables: 'context' (retrieved documents) and 'question' (user query).
QA_PROMPT = PromptTemplate(input_variables=["context", "question"], template=template)
# Constructing a Retrieval-Augmented Generation (RAG) chain.
rag_chain = (retrieval # Step 1: Retrieve relevant document chunks based on the user's question.
| QA_PROMPT # Step 2: Format the retrieved context and question into a structured prompt.
| llm # Step 3: Pass the prompt to the language model (LLM) for answer generation.
| StrOutputParser() # Step 4: Convert the LLM's output into a plain string format.
)
def clean_text(question):
question=re.sub(r'\s+', ' ', question).strip()
question=re.sub(r'\A\d+', '', question).strip()
question = re.sub(r'#\S+', '', question)
question = re.sub(r'@\S+', '', question)
question.replace('\n', ' ')
re.sub(r'\s+(?=(\n+$))', '', question)
pattern = r'[^a-zA-Z0-9\s]'
question=re.sub(pattern, '', question)
return question
def get_rag_chain_response(user_question):
user_question = clean_text(user_question)
return rag_chain.invoke({"question": user_question})
#Below function is used only for testing. Otherwise it is not actually used
def get_context_string_testing(user_question):
ret_arr = get_context_info(user_question)
context_str = ''
for i in range(len(ret_arr)):
# Printing the content of each document chunk (page content).
context_str += ret_arr[i].page_content + '\n '
return context_str
# Gradio elements
# Input from user
in_max_length = 200 # YOUR CODE HERE
in_question = gradio.Textbox(type='text', label='Question', max_length=in_max_length)
# Output response
out_response = gradio.Textbox(type='text', label='Response to question')
# Gradio interface to generate UI link
iface = gradio.Interface( # YOUR CODE HERE
fn=get_rag_chain_response, #get_context_string_testing,
inputs=in_question,
outputs=out_response,
title="RAG implementation",
description="via gradio",)
# YOUR CODE HERE to launch the interface
iface.launch()