whymath commited on
Commit
b6ce469
1 Parent(s): af821b6

Adding base files for Chainlit app with RAG pipeline

Browse files
Files changed (5) hide show
  1. Dockerfile +11 -0
  2. app.py +37 -0
  3. chainlit.md +6 -0
  4. requirements.txt +13 -0
  5. utils.py +69 -0
Dockerfile ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9
2
+ RUN useradd -m -u 1000 user
3
+ USER user
4
+ ENV HOME=/home/user \
5
+ PATH=/home/user/.local/bin:$PATH
6
+ WORKDIR $HOME/app
7
+ COPY --chown=user . $HOME/app
8
+ COPY ./requirements.txt ~/app/requirements.txt
9
+ RUN pip install -r requirements.txt
10
+ COPY . .
11
+ CMD ["chainlit", "run", "app.py", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import chainlit as cl
3
+ from dotenv import load_dotenv
4
+ import utils
5
+
6
+
7
+ load_dotenv()
8
+
9
+
10
+ @cl.on_chat_start
11
+ async def start_chat():
12
+ # Create the RAQA chain and store it in the user session
13
+ raqa_chain = utils.create_raqa_chain_from_docs()
14
+ settings = {
15
+ "chain": raqa_chain
16
+ }
17
+ cl.user_session.set("settings", settings)
18
+
19
+
20
+ @cl.on_message
21
+ async def main(message: cl.Message):
22
+ # Print the message content
23
+ user_query = message.content
24
+ print('user_query =', user_query)
25
+
26
+ # Get the chain from the user session
27
+ settings = cl.user_session.get("settings")
28
+ raqa_chain = settings["chain"]
29
+
30
+ # Generate the response from the chain
31
+ query_response = raqa_chain.invoke({"question" : user_query})
32
+ query_answer = query_response["response"].content
33
+ print('query_answer =', query_answer)
34
+
35
+ # Create and send the message stream
36
+ msg = cl.Message(content=query_answer)
37
+ await msg.send()
chainlit.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+
2
+ # RAG Pipeline Prototype
3
+
4
+ This app uses a RAG pipeline to prototype a virtual student for the teach-to-learn approach, as part of the AIM AIE2 Demo Day Project.
5
+
6
+ *By Yohan Mathew & Jerry Chiang*
requirements.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ipykernel
2
+ numpy
3
+ pandas
4
+ langchain
5
+ langchain-core
6
+ langchain-community
7
+ langchain-openai
8
+ qdrant-client
9
+ tiktoken
10
+ pymupdf
11
+ wandb
12
+ chainlit
13
+ huggingface_hub
utils.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tiktoken
2
+ from langchain.document_loaders import PyMuPDFLoader
3
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
4
+ from langchain_openai.embeddings import OpenAIEmbeddings
5
+ from langchain_community.vectorstores import Qdrant
6
+ from langchain_core.prompts import ChatPromptTemplate
7
+ from langchain_openai import ChatOpenAI
8
+ from operator import itemgetter
9
+ # from langchain.schema.output_parser import StrOutputParser
10
+ from langchain.schema.runnable import RunnablePassthrough
11
+
12
+
13
+ def tiktoken_len(text):
14
+ tokens = tiktoken.encoding_for_model("gpt-3.5-turbo").encode(
15
+ text,
16
+ )
17
+ return len(tokens)
18
+
19
+
20
+ def chunk_documents(docs, tiktoken_len):
21
+ text_splitter = RecursiveCharacterTextSplitter(
22
+ chunk_size = 200,
23
+ chunk_overlap = 0,
24
+ length_function = tiktoken_len,
25
+ )
26
+ split_chunks = text_splitter.split_documents(docs)
27
+ print('len(split_chunks) =', len(split_chunks))
28
+ return split_chunks
29
+
30
+
31
+ def create_raqa_chain_from_docs():
32
+
33
+ # Load the documents from a PDF file using PyMuPDFLoader
34
+ docs = PyMuPDFLoader("https://d18rn0p25nwr6d.cloudfront.net/CIK-0001326801/c7318154-f6ae-4866-89fa-f0c589f2ee3d.pdf").load() # TODO: Update this to enable user to upload PDF
35
+ print("Loaded", len(docs), "documents")
36
+ print(docs[0])
37
+
38
+ # Create a Qdrant vector store from the split chunks and embedding model, and obtain its retriever
39
+ split_chunks = chunk_documents(docs, tiktoken_len)
40
+ embedding_model = OpenAIEmbeddings(model="text-embedding-3-small")
41
+ qdrant_vectorstore = Qdrant.from_documents(
42
+ split_chunks,
43
+ embedding_model,
44
+ location=":memory:",
45
+ collection_name="LoadedPDF",
46
+ )
47
+ qdrant_retriever = qdrant_vectorstore.as_retriever()
48
+
49
+ # Define the RAG prompt template
50
+ RAG_PROMPT = """
51
+ CONTEXT:
52
+ {context}
53
+
54
+ QUERY:
55
+ {question}
56
+
57
+ Use the provided context to answer the provided user query. Only use the provided context to answer the query. If you do not know the answer, respond with "I don't know".
58
+ """
59
+ rag_prompt = ChatPromptTemplate.from_template(RAG_PROMPT)
60
+
61
+ # Create the retrieval augmented QA chain using the Qdrant retriever, RAG prompt, and OpenAI chat model
62
+ openai_chat_model = ChatOpenAI(model="gpt-3.5-turbo")
63
+ retrieval_augmented_qa_chain = (
64
+ {"context": itemgetter("question") | qdrant_retriever, "question": itemgetter("question")}
65
+ | RunnablePassthrough.assign(context=itemgetter("context"))
66
+ | {"response": rag_prompt | openai_chat_model, "context": itemgetter("context")}
67
+ )
68
+
69
+ return retrieval_augmented_qa_chain