Sachin B M commited on
Commit
52e6ad6
·
1 Parent(s): 45ceb20

Add PDF chatbot application

Browse files
Files changed (3) hide show
  1. .gitignore +5 -0
  2. app.py +215 -64
  3. requirements.txt +10 -0
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ .venv/
2
+ .env
3
+ __pycache__/
4
+ *.pyc
5
+ .vscode/
app.py CHANGED
@@ -1,69 +1,220 @@
1
- import gradio as gr
2
- from huggingface_hub import InferenceClient
3
- import streamlit as st
4
-
5
- def respond(
6
- message,
7
- history: list[dict[str, str]],
8
- system_message,
9
- max_tokens,
10
- temperature,
11
- top_p,
12
- hf_token: gr.OAuthToken,
13
- ):
14
- """
15
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
16
- """
17
- client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b")
18
-
19
- messages = [{"role": "system", "content": system_message}]
20
-
21
- messages.extend(history)
22
-
23
- messages.append({"role": "user", "content": message})
24
-
25
- response = ""
26
-
27
- for message in client.chat_completion(
28
- messages,
29
- max_tokens=max_tokens,
30
- stream=True,
31
- temperature=temperature,
32
- top_p=top_p,
33
- ):
34
- choices = message.choices
35
- token = ""
36
- if len(choices) and choices[0].delta.content:
37
- token = choices[0].delta.content
38
-
39
- response += token
40
- yield response
41
-
42
-
43
- """
44
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
45
- """
46
- chatbot = gr.ChatInterface(
47
- respond,
48
- additional_inputs=[
49
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
50
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
51
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
52
- gr.Slider(
53
- minimum=0.1,
54
- maximum=1.0,
55
- value=0.95,
56
- step=0.05,
57
- label="Top-p (nucleus sampling)",
58
- ),
59
- ],
60
  )
61
 
62
- with gr.Blocks() as demo:
63
- with gr.Sidebar():
64
- gr.LoginButton()
65
- chatbot.render()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
 
68
  if __name__ == "__main__":
69
- demo.launch()
 
1
+ import os
2
+ import streamlit as st # type: ignore
3
+
4
+ from dotenv import load_dotenv
5
+ from PyPDF2 import PdfReader
6
+
7
+ from langchain_classic.text_splitter import RecursiveCharacterTextSplitter
8
+ from langchain_cohere import CohereEmbeddings, ChatCohere
9
+ from langchain_community.vectorstores import FAISS
10
+ from langchain_classic.chains import ConversationalRetrievalChain
11
+ from langchain_classic.memory import ConversationBufferMemory
12
+
13
+ load_dotenv()
14
+
15
+ st.set_page_config(
16
+ page_title="Chat with Documents",
17
+ page_icon="📚"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  )
19
 
20
+
21
+ def get_pdf_text(pdf_docs):
22
+ text = ""
23
+
24
+ for pdf in pdf_docs:
25
+ pdf_reader = PdfReader(pdf)
26
+
27
+ for page in pdf_reader.pages:
28
+ text += page.extract_text() or ""
29
+
30
+ return text
31
+
32
+
33
+ def get_text_chunks(text):
34
+ text_splitter = RecursiveCharacterTextSplitter(
35
+ separators=["\n\n", "\n", " ", ""],
36
+ chunk_size=1000,
37
+ chunk_overlap=200,
38
+ length_function=len
39
+ )
40
+
41
+ return text_splitter.split_text(text)
42
+
43
+
44
+ def get_embeddings():
45
+ return CohereEmbeddings(
46
+ model='embed-english-v3.0',
47
+ user_agent="langchain"
48
+ )
49
+
50
+
51
+ def get_conversational_chain(vectorstore):
52
+ llm = ChatCohere(
53
+ model="command-r-08-2024",
54
+ temperature=0
55
+ )
56
+
57
+ memory = ConversationBufferMemory(
58
+ memory_key="chat_history",
59
+ return_messages=True,
60
+ output_key="answer"
61
+ )
62
+
63
+ conversational_chain = ConversationalRetrievalChain.from_llm(
64
+ llm=llm,
65
+ retriever=vectorstore.as_retriever(),
66
+ memory=memory,
67
+ return_source_documents=True
68
+ )
69
+
70
+ return conversational_chain
71
+
72
+
73
+ def handle_userinput(user_question):
74
+ response = st.session_state.conversational_chain.invoke(
75
+ {"question": user_question}
76
+ )
77
+
78
+ answer = response["answer"]
79
+
80
+ st.session_state.chat_history = (
81
+ st.session_state.conversational_chain.memory
82
+ .load_memory_variables({})["chat_history"]
83
+ )
84
+
85
+ for i, message in enumerate(st.session_state.chat_history):
86
+ if message.type == "human":
87
+ with st.chat_message("user"):
88
+ st.write(message.content)
89
+ else:
90
+ with st.chat_message("assistant"):
91
+ st.write(message.content)
92
+
93
+
94
+ def main():
95
+ st.markdown(
96
+ """
97
+ <style>
98
+ .main {
99
+ background: linear-gradient(135deg, #f8fbff 0%, #eef5ff 100%);
100
+ }
101
+ .block-container {
102
+ padding-top: 2rem;
103
+ padding-bottom: 2rem;
104
+ }
105
+ .hero {
106
+ background: linear-gradient(135deg, #0f172a 0%, #1d4ed8 100%);
107
+ padding: 2rem 2rem;
108
+ border-radius: 22px;
109
+ box-shadow: 0 12px 30px rgba(29, 78, 216, 0.18);
110
+ margin-bottom: 1.5rem;
111
+ margin-top: 1.5rem;
112
+ }
113
+ .hero h1 {
114
+ color: white !important;
115
+ font-size: 2.5rem !important;
116
+ font-weight: 800 !important;
117
+ margin: 0 !important;
118
+ }
119
+ .hero p {
120
+ color: #dbeafe !important;
121
+ font-size: 1.05rem !important;
122
+ margin-top: 0.5rem !important;
123
+ margin-bottom: 0 !important;
124
+ }
125
+ </style>
126
+ """,
127
+ unsafe_allow_html=True,
128
+ )
129
+
130
+ st.markdown(
131
+ """
132
+ <div class="hero">
133
+ <h1> AI Chatbot for Your Documents</h1>
134
+ <p>Upload a PDF and ask questions in natural language.</p>
135
+ </div>
136
+ """,
137
+ unsafe_allow_html=True,
138
+ )
139
+
140
+ if "conversational_chain" not in st.session_state:
141
+ st.session_state.conversational_chain = None
142
+
143
+ if "chat_history" not in st.session_state:
144
+ st.session_state.chat_history = []
145
+
146
+ with st.sidebar:
147
+ st.header("Upload Documents")
148
+
149
+ pdf_docs = st.file_uploader(
150
+ "Upload your PDF files",
151
+ type=["pdf"],
152
+ accept_multiple_files=True
153
+ )
154
+
155
+ if st.button("Process Documents"):
156
+ if not pdf_docs:
157
+ st.warning("Please upload at least one PDF.")
158
+ elif not os.getenv("COHERE_API_KEY"):
159
+ st.error("Cohere API key is missing.")
160
+ else:
161
+ try:
162
+ with st.spinner("Processing documents..."):
163
+ raw_text = get_pdf_text(pdf_docs)
164
+
165
+ if not raw_text.strip():
166
+ st.error("No extractable text found in the PDFs.")
167
+ return
168
+
169
+ chunks = get_text_chunks(raw_text)
170
+
171
+ embeddings = get_embeddings()
172
+
173
+ vectorstore = FAISS.from_texts(
174
+ texts=chunks,
175
+ embedding=embeddings
176
+ )
177
+
178
+ st.session_state.conversational_chain = (
179
+ get_conversational_chain(vectorstore)
180
+ )
181
+
182
+ st.session_state.chat_history = []
183
+
184
+ st.success("Documents processed successfully!")
185
+
186
+ except Exception as e:
187
+ st.error(f"Error processing documents: {e}")
188
+
189
+ user_question = st.chat_input("Ask a question about your PDFs")
190
+
191
+ if user_question:
192
+ if st.session_state.conversational_chain is None:
193
+ st.warning("Please upload and process your documents first.")
194
+ else:
195
+ with st.chat_message("user"):
196
+ st.write(user_question)
197
+
198
+ with st.chat_message("assistant"):
199
+ with st.spinner("Thinking..."):
200
+ try:
201
+ response = (
202
+ st.session_state.conversational_chain.invoke(
203
+ {"question": user_question}
204
+ )
205
+ )
206
+ st.write(response["answer"])
207
+
208
+ st.session_state.chat_history = (
209
+ st.session_state.conversational_chain
210
+ .memory.load_memory_variables(
211
+ {}
212
+ )["chat_history"]
213
+ )
214
+
215
+ except Exception as e:
216
+ st.error(f"Error generating answer: {e}")
217
 
218
 
219
  if __name__ == "__main__":
220
+ main()
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ streamlit
2
+ gradio
3
+ python-dotenv
4
+ PyPDF2
5
+ langchain
6
+ langchain-community
7
+ langchain-cohere
8
+ langchain-classic
9
+ langchain-text-splitters
10
+ faiss-cpu