kdembla commited on
Commit
13df762
·
verified ·
1 Parent(s): a43a785

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +294 -81
app.py CHANGED
@@ -2,101 +2,314 @@ import gradio as gr
2
  from langchain_openai import ChatOpenAI
3
  from langchain.memory import ConversationBufferMemory
4
  from langchain.chains import ConversationalRetrievalChain
5
- from langchain_community.document_loaders import UnstructuredPDFLoader
6
- from langchain_openai import OpenAIEmbeddings
 
7
  from langchain.text_splitter import RecursiveCharacterTextSplitter
8
- from langchain_community.vectorstores import DocArrayInMemorySearch
9
- from langchain_core.runnables import RunnableLambda, RunnablePassthrough
10
- from langchain.prompts import PromptTemplate
11
-
12
- import nltk
13
- nltk.download('punkt')
14
- #from langfuse.callback import CallbackHandler
15
-
16
  import os
 
17
  from dotenv import load_dotenv
18
 
 
19
  load_dotenv()
20
- API_KEY = os.getenv("OPENAI_API_KEY")
21
 
22
- # Function to create the chat chain
23
- def create_chat_chain(file_path, openai_model):
24
- docs = []
25
- for filepath in file_path:
26
- loader = UnstructuredPDFLoader(filepath)
27
- docs.extend(loader.load())
28
 
29
- # Splitting txt
30
- text_splitter = RecursiveCharacterTextSplitter(
31
- chunk_size=500,
32
- chunk_overlap=100
33
- )
34
- split_documents = text_splitter.split_documents(docs)
35
 
36
- #Creating embeddings
37
- embeddings = OpenAIEmbeddings(openai_api_key=API_KEY)
38
- vectordb = DocArrayInMemorySearch.from_documents(split_documents, embeddings)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- #Retriever setip
41
- retriever = vectordb.as_retriever(
42
- search_type='mmr'
43
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
- #memory setup
46
- memory = ConversationBufferMemory(
47
- memory_key='chat_history',
48
- return_messages=True,
49
- output_key='answer' # Explicitly set the output key to avoid ambiguity
50
- )
 
51
 
52
- llm_def = ChatOpenAI(model=openai_model, temperature=0, api_key=API_KEY, max_tokens=1100)
53
- chain = ConversationalRetrievalChain.from_llm(
54
- llm=llm_def,
55
- retriever=retriever,
56
- memory=memory,
57
- return_source_documents=True,
58
- verbose=True
59
- #callbacks=[langfuse_handler]
60
- )
61
- return chain
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- # Function to process user input
64
- def process_input(chain, user_message):
65
- inputs = {"question": user_message}
66
- outputs = chain(inputs)
67
- return outputs['answer']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
- if __name__ == "__main__":
70
- openai_model = "gpt-4o"
71
- file_path = [
72
- r"sat-practest.pdf"
73
- ]
74
- chain = create_chat_chain(file_path, openai_model)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
- # Gradio UI
77
- with gr.Blocks() as demo:
78
- with gr.Row():
79
- gr.Markdown("<h1 style='text-align: center; width: 100%;'>RAG with Memory</h1>")
80
- with gr.Row():
81
- with gr.Column(scale=1):
82
- gr.Markdown("**Here's how to use this demo:**")
83
- gr.Markdown("""This a conversational agent responsible for summarizing, and giving key highlights about the atached pdf file (The SAT Practice Test 1) .\n
84
- Feel free to experiment with your own different queries and usage or accesibility requests!
85
- """)
86
- with gr.Column(scale=3):
87
- ex = ["Which question contains information about Navajo Nation legislator Annie Dodge Wauneka?","What does question 7 in module 2 of reading and writing ask for?","How many questions are there in module 2 of the reading and writing section?","Which question of which section talks about the poem 'To You' by Walt Whitman?"]
88
- chatbot = gr.Chatbot()
89
- msg = gr.Textbox()
90
- gr.Examples(ex, msg)
91
- clear = gr.Button("Clear Chat History")
92
 
93
- def handle_message(user_message, history):
94
- answer = process_input(chain, user_message)
95
- history.append([user_message, answer])
96
- return "", history
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
- msg.submit(handle_message, [msg, chatbot], [msg, chatbot])
99
- clear.click(lambda: chain.memory.clear(), None, chatbot)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
- demo.queue()
102
- demo.launch()
 
 
 
2
  from langchain_openai import ChatOpenAI
3
  from langchain.memory import ConversationBufferMemory
4
  from langchain.chains import ConversationalRetrievalChain
5
+ from langchain_community.document_loaders import PyPDFLoader
6
+ from langchain_community.embeddings import HuggingFaceEmbeddings
7
+ from langchain_community.vectorstores import FAISS
8
  from langchain.text_splitter import RecursiveCharacterTextSplitter
 
 
 
 
 
 
 
 
9
  import os
10
+ import tempfile
11
  from dotenv import load_dotenv
12
 
13
+ # Load environment variables
14
  load_dotenv()
 
15
 
16
+ # Global variable to store the chat chain and vector store
17
+ chat_chain = None
18
+ vectordb = None
 
 
 
19
 
20
+ # For debugging
21
+ import sys
22
+ print("Python version:", sys.version)
 
 
 
23
 
24
+ def create_chat_chain(file_path):
25
+ """
26
+ Create a conversational chain for the chat interface.
27
+
28
+ Args:
29
+ file_path: Path to the uploaded PDF file
30
+
31
+ Returns:
32
+ tuple: (status_message, chain, vector_store)
33
+ """
34
+ global vectordb
35
+
36
+ try:
37
+ # Load the PDF document
38
+ print(f"Loading document: {file_path}")
39
+ loader = PyPDFLoader(file_path)
40
+ docs = loader.load()
41
+
42
+ if not docs:
43
+ return "Error: No content could be extracted from the PDF.", None, None
44
+
45
+ print(f"Successfully loaded {len(docs)} pages from the document")
46
 
47
+ # Split text into chunks
48
+ print("Splitting documents into chunks...")
49
+ text_splitter = RecursiveCharacterTextSplitter(
50
+ chunk_size=1500, # Increased chunk size for better context
51
+ chunk_overlap=300, # Increased overlap for better temporal context
52
+ length_function=len
53
+ )
54
+ split_documents = text_splitter.split_documents(docs)
55
+ print(f"Split into {len(split_documents)} chunks")
56
+
57
+ # Create embeddings
58
+ print("Creating embeddings...")
59
+ embeddings = HuggingFaceEmbeddings(
60
+ model_name="sentence-transformers/all-mpnet-base-v2"
61
+ )
62
+
63
+ # Create vector store
64
+ print("Creating vector store...")
65
+ vectordb = FAISS.from_documents(split_documents, embeddings)
66
+
67
+ # Set up retriever with more context
68
+ retriever = vectordb.as_retriever(
69
+ search_type="mmr",
70
+ search_kwargs={
71
+ "k": 6, # Increased number of documents to retrieve
72
+ "fetch_k": 20 # Increased fetch size for better context
73
+ }
74
+ )
75
 
76
+ # Set up memory with more context
77
+ memory = ConversationBufferMemory(
78
+ memory_key="chat_history",
79
+ return_messages=True,
80
+ output_key="answer",
81
+ input_key="question"
82
+ )
83
 
84
+ # Initialize the language model
85
+ print("Initializing language model...")
86
+ llm = ChatOpenAI(
87
+ model_name="gpt-3.5-turbo",
88
+ temperature=0.2,
89
+ max_tokens=1500
90
+ )
91
+
92
+ # Create the conversational chain with better configuration
93
+ print("Creating conversation chain...")
94
+ from langchain.prompts import PromptTemplate
95
+ from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT
96
+
97
+ # Create a proper prompt template
98
+ prompt_template = """Use the provided documents to answer the question.
99
+ Be specific and accurate with temporal references.
100
+ If you cannot find the information in the documents, say so clearly.
101
+
102
+ {context}
103
+
104
+ Question: {question}
105
+ Answer:"""
106
+
107
+ PROMPT = PromptTemplate(
108
+ template=prompt_template,
109
+ input_variables=["context", "question"]
110
+ )
111
+
112
+ # Create the chain with proper configuration
113
+ chain = ConversationalRetrievalChain.from_llm(
114
+ llm=llm,
115
+ retriever=retriever,
116
+ memory=memory,
117
+ return_source_documents=True,
118
+ combine_docs_chain_kwargs={
119
+ "prompt": PROMPT
120
+ }
121
+ )
122
+
123
+ print("\nChain configuration:")
124
+ print(f"LLM model: gpt-3.5-turbo") # Hardcoded since we know the model
125
+ print(f"Retriever config: {retriever.search_kwargs}")
126
+ print(f"Memory type: {type(memory).__name__}")
127
+ print(f"Prompt template: {prompt_template}")
128
+
129
+ print("Chat chain created successfully!")
130
+ return "Document processed successfully! You can now ask questions about the PDF.", chain, vectordb
131
+
132
+ except Exception as e:
133
+ error_msg = f"Error processing document: {str(e)}"
134
+ print(error_msg)
135
+ import traceback
136
+ traceback.print_exc()
137
+ return error_msg, None, None
138
 
139
+ def process_user_input(user_message, chat_history):
140
+ """
141
+ Process user input and generate a response using the chat chain.
142
+
143
+ Args:
144
+ user_message (str): User's message
145
+ chat_history: Current chat history
146
+
147
+ Returns:
148
+ str: Generated response
149
+ """
150
+ global chat_chain
151
+ if chat_chain is None:
152
+ return "Please upload a PDF file first."
153
+
154
+ try:
155
+ print(f"Processing question: {user_message}")
156
+ print(f"Current chat history: {len(chat_history)} messages")
157
+
158
+ # Get response from the chain
159
+ response = chat_chain({"question": user_message, "chat_history": chat_history})
160
+
161
+ return response["answer"]
162
+
163
+ except Exception as e:
164
+ import traceback
165
+ print("\nError details:")
166
+ print(f"Error type: {type(e).__name__}")
167
+ print(f"Error message: {str(e)}")
168
+ traceback.print_exc()
169
+
170
+ if isinstance(e, ValueError):
171
+ error_msg = f"Value error: {str(e)}"
172
+ else:
173
+ error_msg = "An unexpected error occurred. Please try again."
174
+
175
+ return error_msg
176
 
177
+ def handle_message(user_message, chat_history):
178
+ """
179
+ Handle incoming messages and update chat history.
180
+
181
+ Args:
182
+ user_message (str): User's message
183
+ history: Current chat history
184
+
185
+ Returns:
186
+ tuple: Empty message and updated history
187
+ """
188
+ if not user_message.strip():
189
+ return "", chat_history
190
+
191
+ # Get response from the chain
192
+ response = process_user_input(user_message, chat_history)
193
+
194
+ # Update chat history
195
+ chat_history.append((user_message, response))
196
+
197
+ return "", chat_history
198
 
199
+ def clear_chat():
200
+ """
201
+ Clear the conversation history.
202
+
203
+ Returns:
204
+ list: Empty list to clear the chat interface
205
+ """
206
+ global chat_chain
207
+ if chat_chain is not None and hasattr(chat_chain, 'memory') and chat_chain.memory is not None:
208
+ chat_chain.memory.clear()
209
+ return []
 
 
 
 
 
210
 
211
+ def process_uploaded_file(file):
212
+ """
213
+ Process the uploaded PDF file and initialize the chat chain.
214
+
215
+ Args:
216
+ file: Uploaded file object from Gradio
217
+
218
+ Returns:
219
+ str: Status message
220
+ """
221
+ global chat_chain, vectordb
222
+
223
+ if file is None:
224
+ return "No file uploaded. Please upload a PDF file."
225
+
226
+ try:
227
+ # Get the file path from the Gradio file object
228
+ file_path = file.name
229
+
230
+ # Validate file type
231
+ if not file_path.lower().endswith('.pdf'):
232
+ return "Error: Only PDF files are supported. Please upload a PDF file."
233
+
234
+ # Create the chat chain with the uploaded file
235
+ status_msg, new_chain, new_vectordb = create_chat_chain(file_path)
236
+
237
+ if new_chain is not None and new_vectordb is not None:
238
+ chat_chain = new_chain
239
+ vectordb = new_vectordb
240
+
241
+ return status_msg
242
+
243
+ except Exception as e:
244
+ import traceback
245
+ traceback.print_exc()
246
+ return f"Error processing file: {str(e)}"
247
 
248
+ # Create the Gradio interface
249
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
250
+ gr.Markdown("""
251
+ # RAGBot with Memory
252
+ Upload a PDF file and ask questions about its content.
253
+ """)
254
+
255
+ # File upload component
256
+ file_output = gr.File(label="Upload a PDF file")
257
+ upload_btn = gr.Button("Process PDF")
258
+ status = gr.Markdown("Please upload a PDF file to begin.")
259
+
260
+ # Chat interface
261
+ chatbot = gr.Chatbot(height=400, label="Chat History")
262
+ msg = gr.Textbox(placeholder="Type your message here...", label="Your Message")
263
+
264
+ # Action buttons
265
+ with gr.Row():
266
+ send_btn = gr.Button("Send")
267
+ clear_btn = gr.Button("Clear Conversation")
268
+
269
+ # Example questions
270
+ examples = [
271
+ "What is this document about?",
272
+ "Can you summarize the key points?",
273
+ "What are the main topics covered?"
274
+ ]
275
+
276
+ # Add examples
277
+ with gr.Row():
278
+ for example in examples:
279
+ gr.Examples(
280
+ examples=[[example]],
281
+ inputs=msg,
282
+ label=f"Try: {example[:20]}..."
283
+ )
284
+
285
+ # Event handlers
286
+ upload_btn.click(
287
+ process_uploaded_file,
288
+ inputs=file_output,
289
+ outputs=status
290
+ )
291
+
292
+ def handle_click(user_message, history):
293
+ return handle_message(user_message, history)
294
+
295
+ msg.submit(
296
+ handle_click,
297
+ inputs=[msg, chatbot],
298
+ outputs=[msg, chatbot]
299
+ )
300
+
301
+ send_btn.click(
302
+ handle_click,
303
+ inputs=[msg, chatbot],
304
+ outputs=[msg, chatbot]
305
+ )
306
+
307
+ clear_btn.click(
308
+ clear_chat,
309
+ outputs=chatbot
310
+ )
311
 
312
+ # Launch the interface
313
+ if __name__ == "__main__":
314
+ print("Starting RAGBot application...")
315
+ demo.launch(share=False)