Spaces:
Sleeping
Sleeping
from langchain_community.document_loaders import PyMuPDFLoader | |
from langchain_text_splitters import RecursiveCharacterTextSplitter | |
from langchain_openai import AzureOpenAIEmbeddings, AzureChatOpenAI, OpenAIEmbeddings, ChatOpenAI | |
from operator import itemgetter | |
from langchain_core.runnables import RunnablePassthrough | |
from langchain_qdrant import QdrantVectorStore | |
from qdrant_client import QdrantClient | |
from qdrant_client.http.models import Distance, VectorParams | |
from langchain.prompts import ChatPromptTemplate | |
import tiktoken | |
import os | |
from dotenv import load_dotenv | |
# Load environment variables from .env file | |
load_dotenv() | |
print(os.getenv("AZURE_OPENAI_ENDPOINT")) | |
### SETUP FUNCTIONS ### | |
def tiktoken_len(text): | |
tokens = tiktoken.encoding_for_model("gpt-4o").encode( | |
text, | |
) | |
return len(tokens) | |
def setup_vector_db(): | |
# Get the directory of the current file | |
current_file_directory = os.path.dirname(os.path.abspath(__file__)) | |
# Change the working directory to the current file's directory | |
os.chdir(current_file_directory) | |
# Load the NIST AI document | |
PDF_LINK = "data/nist_ai.pdf" | |
loader = PyMuPDFLoader(file_path=PDF_LINK) | |
nist_doc = loader.load() | |
text_splitter = RecursiveCharacterTextSplitter( | |
chunk_size = 500, | |
chunk_overlap = 100, | |
length_function = tiktoken_len, | |
) | |
nist_chunks = text_splitter.split_documents(nist_doc) | |
embeddings_small = AzureOpenAIEmbeddings(azure_deployment="text-embedding-3-small") | |
# embeddings_small = OpenAIEmbeddings(model="text-embedding-3-small") | |
qdrant_client = QdrantClient(":memory:") # set Qdrant DB and its location (in-memory) | |
qdrant_client.create_collection( | |
collection_name="NIST_AI", | |
vectors_config=VectorParams(size=1536, distance=Distance.COSINE), | |
) | |
qdrant_vector_store = QdrantVectorStore( | |
client=qdrant_client, | |
collection_name="NIST_AI", | |
embedding=embeddings_small, | |
) # create a QdrantVectorStore object with the above specified client, collection name, and embedding model. | |
qdrant_vector_store.add_documents(nist_chunks) # add the documents to the QdrantVectorStore | |
retriever = qdrant_vector_store.as_retriever() | |
return retriever | |
### VARIABLES ### | |
# define a global variable to store the retriever object | |
retriever = setup_vector_db() | |
qa_gpt4_llm = AzureChatOpenAI(azure_deployment="gpt-4o-mini", temperature=0) # GPT-4o-mini model | |
# qa_gpt4_llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) # GPT-4o-mini model | |
# define a template for the RAG model | |
rag_template = """ | |
You are a helpful assistant that helps users find information and answer their question. | |
You MUST use ONLY the available context to answer the question. | |
If necessary information to answer the question cannot be found in the provided context, you MUST "I don't know." | |
Question: | |
{question} | |
Context: | |
{context} | |
""" | |
# create rag prompt object from the template | |
prompt = ChatPromptTemplate.from_template(rag_template) | |
# update the chain with LLM, prompt, and question variable. | |
retrieval_augmented_qa_chain = ( | |
{"context": itemgetter("question") | retriever, "question": itemgetter("question")} | |
| RunnablePassthrough.assign(context=itemgetter("context")) | |
| {"response": prompt | qa_gpt4_llm, "context": itemgetter("context"), "question": itemgetter("question")} | |
) | |
### FUNCTIONS ### | |
def get_response(query, history): | |
"""A helper function to get the response from the RAG model and return it to the UI.""" | |
response = retrieval_augmented_qa_chain.invoke({"question" : query}) | |
return response["response"].content |