Spaces:
Sleeping
Sleeping
import os | |
import chainlit as cl | |
import tiktoken | |
import openai | |
from dotenv import load_dotenv | |
from operator import itemgetter | |
from langchain_openai import ChatOpenAI | |
from langchain import text_splitter | |
from langchain.text_splitter import RecursiveCharacterTextSplitter | |
from langchain_community.document_loaders import PyMuPDFLoader | |
from langchain_community.embeddings import OpenAIEmbeddings | |
from langchain_community.vectorstores import Qdrant | |
from langchain.prompts import ChatPromptTemplate | |
from langchain.chat_models import ChatOpenAI | |
from operator import itemgetter | |
from langchain.schema.runnable import RunnablePassthrough | |
# GLOBAL SCOPE - ENTIRE APPLICATION HAS ACCESS TO VALUES SET IN THIS SCOPE # | |
# ---- ENV VARIABLES ---- # | |
load_dotenv() | |
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") | |
# Initialize OpenAI client after loading the environment variables | |
openai.api_key = OPENAI_API_KEY | |
# -- RETRIEVAL -- # | |
""" | |
1. Load Documents from Text File | |
2. Split Documents into Chunks | |
3. Push files into our vectorstore | |
""" | |
### 1. CREATE TEXT LOADER AND LOAD DOCUMENTS | |
source_file = PyMuPDFLoader("./data/airbnb-10k.pdf") | |
loaded_file = source_file.load() | |
def tiktoken_len(text): | |
tokens = tiktoken.encoding_for_model("gpt-4o").encode(text) | |
return len(tokens) | |
text_splitter = RecursiveCharacterTextSplitter( | |
chunk_size = 100, | |
chunk_overlap = 30, | |
length_function = tiktoken_len, | |
) | |
chunks = text_splitter.split_documents(loaded_file) | |
#-----Embedding and Vector Store Setup-----# | |
# Load OpenAI Embeddings Model | |
embeddings = OpenAIEmbeddings(model="text-embedding-3-large") | |
# Creating Qdrant Vector Store | |
qdrant_vector_store = Qdrant.from_documents( | |
chunks, | |
embeddings, | |
location=":memory:", | |
collection_name="airbnbdocs", | |
) | |
# Create a Retriever | |
retriever = qdrant_vector_store.as_retriever() | |
#-----Prompt Template and Language Model Setup-----# | |
# Define the prompt template | |
template = """Answer the query from the user based only on the context provided. \n | |
If you cannot answer the question with the context, please respond with 'I don't believe I have the answer to that question, could you try asking it again in a different way?'. | |
Please also provide examples form the context material that illustrate how you came to your answer. | |
Context: | |
{context} | |
Question: | |
{question} | |
""" | |
prompt = ChatPromptTemplate.from_template(template) | |
chat_llm = ChatOpenAI(model_name="gpt-4o", temperature=0) | |
retrieval_augmented_qa_chain = ( | |
{"context": itemgetter("question") | retriever, "question": itemgetter("question")} | |
| RunnablePassthrough.assign(context=itemgetter("context")) | |
| {"response": prompt | chat_llm, "context": itemgetter("context")} | |
) | |
#-----Chainlit Integration-----# | |
async def start_chat(): | |
settings = { | |
"model": "gpt-4o", | |
"temperature": 0, | |
"max_tokens": 500, | |
"top_p": 1, | |
"frequency_penalty": 0, | |
"presence_penalty": 0, | |
} | |
cl.user_session.set("settings", settings) | |
# Processes incoming messages from the user and sends a response through a series of steps: | |
# (1) Retrieves the user's settings | |
# (2) Invokes the RAG chain with the user's message | |
# (3) Extracts the content from the response and sends it back to the user | |
async def handle_message(message: cl.Message): | |
settings = cl.user_session.get("settings") | |
response = retrieval_augmented_qa_chain.invoke({"question": message.content}) | |
# Extracting and sending just the content | |
content = response["response"].content | |
pretty_content = content.strip() # Remove any leading/trailing whitespace | |
await cl.Message(content=pretty_content).send() | |