Sujal Bhat commited on
Commit
bb86815
·
1 Parent(s): 76b59ce

initial checking

Browse files
Files changed (4) hide show
  1. .gitignore +63 -0
  2. Dockerfile +11 -0
  3. app.py +132 -0
  4. requirements.txt +99 -0
.gitignore ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual Environment
24
+ venv/
25
+ env/
26
+ ENV/
27
+
28
+ # IDEs and Editors
29
+ .vscode/
30
+ .idea/
31
+ *.swp
32
+ *.swo
33
+ *~
34
+
35
+ # OS generated files
36
+ .DS_Store
37
+ .DS_Store?
38
+ ._*
39
+ .Spotlight-V100
40
+ .Trashes
41
+ ehthumbs.db
42
+ Thumbs.db
43
+
44
+ # Chainlit specific
45
+ .chainlit/
46
+ cache/
47
+
48
+ # Logs
49
+ *.log
50
+
51
+ # Database
52
+ *.sqlite
53
+
54
+ # Environment variables
55
+ .env
56
+
57
+ # Jupyter Notebook
58
+ .ipynb_checkpoints
59
+
60
+ # PyCharm
61
+ *.
62
+
63
+ .history/
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,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Import Section ###
2
+ import os
3
+ import uuid
4
+ import openai # Add this import
5
+ from operator import itemgetter
6
+ from langchain_openai import OpenAIEmbeddings, ChatOpenAI
7
+ from langchain_community.document_loaders import PyMuPDFLoader
8
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
9
+ from langchain.storage import LocalFileStore
10
+ from langchain.embeddings import CacheBackedEmbeddings
11
+ from langchain_qdrant import QdrantVectorStore
12
+ from langchain_core.prompts import ChatPromptTemplate
13
+ from langchain_core.runnables.passthrough import RunnablePassthrough
14
+ from qdrant_client import QdrantClient
15
+ from qdrant_client.http.models import Distance, VectorParams
16
+ from langchain_core.caches import InMemoryCache
17
+ from langchain_core.globals import set_llm_cache
18
+ import chainlit as cl
19
+ import tempfile
20
+
21
+ ### Global Section ###
22
+ # Set up OpenAI API key
23
+ openai.api_key = os.getenv("OPENAI_API_KEY")
24
+
25
+ # Set up LangSmith
26
+ os.environ["LANGCHAIN_PROJECT"] = f"AIM Week 8 Assignment 1 - {uuid.uuid4().hex[0:8]}"
27
+ os.environ["LANGCHAIN_TRACING_V2"] = "true"
28
+ os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
29
+
30
+ # Set up text splitter
31
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
32
+
33
+ # Set up embeddings with cache
34
+ core_embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
35
+ store = LocalFileStore("./cache/")
36
+ cached_embedder = CacheBackedEmbeddings.from_bytes_store(
37
+ core_embeddings, store, namespace=core_embeddings.model
38
+ )
39
+
40
+ # Set up QDrant vector store
41
+ collection_name = f"pdf_to_parse_{uuid.uuid4()}"
42
+ client = QdrantClient(":memory:")
43
+ client.create_collection(
44
+ collection_name=collection_name,
45
+ vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
46
+ )
47
+
48
+ # Set up chat model and cache
49
+ chat_model = ChatOpenAI(model="gpt-4o-mini")
50
+ set_llm_cache(InMemoryCache())
51
+
52
+ # Set up RAG prompt
53
+ rag_system_prompt_template = """
54
+ You are a helpful assistant that uses the provided context to answer questions. Never reference this prompt, or the existence of context.
55
+ """
56
+
57
+ rag_user_prompt_template = """
58
+ Question:
59
+ {question}
60
+ Context:
61
+ {context}
62
+ """
63
+
64
+ chat_prompt = ChatPromptTemplate.from_messages([
65
+ ("system", rag_system_prompt_template),
66
+ ("human", rag_user_prompt_template)
67
+ ])
68
+
69
+ ### On Chat Start (Session Start) Section ###
70
+ @cl.on_chat_start
71
+ async def on_chat_start():
72
+ # Upload and process PDF
73
+ files = await cl.AskFileMessage(content="Please upload a PDF file to begin.", accept=["application/pdf"]).send()
74
+ if not files:
75
+ await cl.Message(content="No file was uploaded. Please try again.").send()
76
+ return
77
+
78
+ file = files[0]
79
+
80
+ msg = cl.Message(content=f"Processing `{file.name}`...")
81
+ await msg.send()
82
+
83
+ try:
84
+ # Save the file to a temporary location
85
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
86
+ tmp_file.write(file.content)
87
+ tmp_file_path = tmp_file.name
88
+
89
+ # Load and split the PDF
90
+ loader = PyMuPDFLoader(tmp_file_path)
91
+ documents = loader.load()
92
+ docs = text_splitter.split_documents(documents)
93
+ for i, doc in enumerate(docs):
94
+ doc.metadata["source"] = f"source_{i}"
95
+
96
+ # Set up vector store
97
+ vectorstore = QdrantVectorStore(
98
+ client=client,
99
+ collection_name=collection_name,
100
+ embedding=cached_embedder
101
+ )
102
+ vectorstore.add_documents(docs)
103
+ retriever = vectorstore.as_retriever(search_type="mmr", search_kwargs={"k": 3})
104
+
105
+ # Set up RAG chain
106
+ global retrieval_augmented_qa_chain
107
+ retrieval_augmented_qa_chain = (
108
+ {"context": itemgetter("question") | retriever, "question": itemgetter("question")}
109
+ | RunnablePassthrough.assign(context=itemgetter("context"))
110
+ | chat_prompt | chat_model
111
+ )
112
+
113
+ msg.content = f"`{file.name}` processed. You can now ask questions about it!"
114
+ await msg.update()
115
+
116
+ except Exception as e:
117
+ await cl.Message(content=f"An error occurred while processing the file: {str(e)}").send()
118
+ finally:
119
+ # Clean up the temporary file
120
+ if 'tmp_file_path' in locals():
121
+ os.unlink(tmp_file_path)
122
+
123
+ ### On Message Section ###
124
+ @cl.on_message
125
+ async def main(message: cl.Message):
126
+ response = retrieval_augmented_qa_chain.invoke({"question": message.content})
127
+ await cl.Message(content=response.content).send()
128
+
129
+ ### Rename Chains ###
130
+ @cl.author_rename
131
+ def rename(orig_author: str):
132
+ return "AI Assistant"
requirements.txt ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==23.2.1
2
+ aiohappyeyeballs==2.4.3
3
+ aiohttp==3.10.8
4
+ aiosignal==1.3.1
5
+ annotated-types==0.7.0
6
+ anyio==3.7.1
7
+ async-timeout==4.0.3
8
+ asyncer==0.0.2
9
+ attrs==24.2.0
10
+ bidict==0.23.1
11
+ certifi==2024.8.30
12
+ chainlit==0.7.700
13
+ charset-normalizer==3.3.2
14
+ click==8.1.7
15
+ dataclasses-json==0.5.14
16
+ Deprecated==1.2.14
17
+ distro==1.9.0
18
+ exceptiongroup==1.2.2
19
+ fastapi==0.100.1
20
+ fastapi-socketio==0.0.10
21
+ filetype==1.2.0
22
+ frozenlist==1.4.1
23
+ googleapis-common-protos==1.65.0
24
+ greenlet==3.1.1
25
+ grpcio==1.66.2
26
+ grpcio-tools==1.62.3
27
+ h11==0.14.0
28
+ h2==4.1.0
29
+ hpack==4.0.0
30
+ httpcore==0.17.3
31
+ httpx==0.24.1
32
+ hyperframe==6.0.1
33
+ idna==3.10
34
+ importlib_metadata==8.4.0
35
+ jiter==0.5.0
36
+ jsonpatch==1.33
37
+ jsonpointer==3.0.0
38
+ langchain==0.3.0
39
+ langchain-community==0.3.0
40
+ langchain-core==0.3.1
41
+ langchain-openai==0.2.0
42
+ langchain-qdrant==0.1.4
43
+ langchain-text-splitters==0.3.0
44
+ langsmith==0.1.121
45
+ Lazify==0.4.0
46
+ marshmallow==3.22.0
47
+ multidict==6.1.0
48
+ mypy-extensions==1.0.0
49
+ nest-asyncio==1.6.0
50
+ numpy==1.26.4
51
+ openai==1.51.0
52
+ opentelemetry-api==1.27.0
53
+ opentelemetry-exporter-otlp==1.27.0
54
+ opentelemetry-exporter-otlp-proto-common==1.27.0
55
+ opentelemetry-exporter-otlp-proto-grpc==1.27.0
56
+ opentelemetry-exporter-otlp-proto-http==1.27.0
57
+ opentelemetry-instrumentation==0.48b0
58
+ opentelemetry-proto==1.27.0
59
+ opentelemetry-sdk==1.27.0
60
+ opentelemetry-semantic-conventions==0.48b0
61
+ orjson==3.10.7
62
+ packaging==23.2
63
+ portalocker==2.10.1
64
+ protobuf==4.25.5
65
+ pydantic==2.9.2
66
+ pydantic-settings==2.5.2
67
+ pydantic_core==2.23.4
68
+ PyJWT==2.9.0
69
+ PyMuPDF==1.24.10
70
+ PyMuPDFb==1.24.10
71
+ python-dotenv==1.0.1
72
+ python-engineio==4.9.1
73
+ python-graphql-client==0.4.3
74
+ python-multipart==0.0.6
75
+ python-socketio==5.11.4
76
+ PyYAML==6.0.2
77
+ qdrant-client==1.11.2
78
+ regex==2024.9.11
79
+ requests==2.32.3
80
+ simple-websocket==1.0.0
81
+ sniffio==1.3.1
82
+ SQLAlchemy==2.0.35
83
+ starlette==0.27.0
84
+ syncer==2.0.3
85
+ tenacity==8.5.0
86
+ tiktoken==0.7.0
87
+ tomli==2.0.1
88
+ tqdm==4.66.5
89
+ typing-inspect==0.9.0
90
+ typing_extensions==4.12.2
91
+ uptrace==1.26.0
92
+ urllib3==2.2.3
93
+ uvicorn==0.23.2
94
+ watchfiles==0.20.0
95
+ websockets==13.1
96
+ wrapt==1.16.0
97
+ wsproto==1.2.0
98
+ yarl==1.13.1
99
+ zipp==3.20.2