import os from typing import List from langchain.embeddings.openai import OpenAIEmbeddings from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.vectorstores import FAISS from langchain.chains import ( ConversationalRetrievalChain, ) from langchain_community.document_loaders import PyPDFLoader from langchain_community.chat_models import ChatOpenAI from langchain.prompts.chat import ( ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate, ) from langchain.docstore.document import Document from langchain.memory import ChatMessageHistory, ConversationBufferMemory from dotenv import load_dotenv import chainlit as cl load_dotenv() text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100) system_template = """Answer the question based only on the following context. If you cannot answer the question with the context, please respond with 'I don't know': Context: {context} Question: {question} ---------------- {summaries}""" messages = [ SystemMessagePromptTemplate.from_template(system_template), HumanMessagePromptTemplate.from_template("{question}"), ] prompt = ChatPromptTemplate.from_messages(messages) chain_type_kwargs = {"prompt": prompt} @cl.on_chat_start async def on_chat_start(): msg = cl.Message( content=f"Processing Nvidia.pdf..." ) await msg.send() # Load PDF directly from local data directory pypdf_loader = PyPDFLoader("data/nvidia.pdf") texts = pypdf_loader.load_and_split() texts = [text.page_content for text in texts] # Create metadata for each chunk metadatas = [{"source": f"{i}-pl"} for i in range(len(texts))] # Create a FAISS vectorstore embeddings = OpenAIEmbeddings() docsearch = await cl.make_async(FAISS.from_texts)( texts, embeddings, metadatas=metadatas ) message_history = ChatMessageHistory() memory = ConversationBufferMemory( memory_key="chat_history", output_key="answer", chat_memory=message_history, return_messages=True, ) # Create a chain that uses the FAISS vectorstore chain = ConversationalRetrievalChain.from_llm( ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0, streaming=True), chain_type="stuff", retriever=docsearch.as_retriever(), memory=memory, return_source_documents=True, ) # Let the user know that the system is ready msg.content = f"Processing Nvidia.pdf done. You can now ask questions!" await msg.update() cl.user_session.set("chain", chain) @cl.on_message async def main(message): chain = cl.user_session.get("chain") # type: ConversationalRetrievalChain cb = cl.AsyncLangchainCallbackHandler() res = await chain.acall(message.content, callbacks=[cb]) answer = res["answer"] source_documents = res["source_documents"] # type: List[Document] text_elements = [] # type: List[cl.Text] if source_documents: for source_idx, source_doc in enumerate(source_documents): source_name = f"source_{source_idx}" # Create the text element referenced in the message text_elements.append( cl.Text(content=source_doc.page_content, name=source_name) ) source_names = [text_el.name for text_el in text_elements] if source_names: answer += f"\nSources: {', '.join(source_names)}" else: answer += "\nNo sources found" await cl.Message(content=answer, elements=text_elements).send()