File size: 9,539 Bytes
0118b41
 
 
 
13df762
 
 
0118b41
 
13df762
0118b41
 
13df762
0118b41
 
13df762
 
 
0118b41
13df762
 
 
0118b41
13df762
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0118b41
13df762
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0118b41
13df762
 
 
 
 
 
 
0118b41
13df762
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0118b41
13df762
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0118b41
13df762
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0118b41
13df762
 
 
 
 
 
 
 
 
 
 
0118b41
13df762
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0118b41
13df762
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0118b41
13df762
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import gradio as gr
from langchain_openai import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
import os
import tempfile
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

# Global variable to store the chat chain and vector store
chat_chain = None
vectordb = None

# For debugging
import sys
print("Python version:", sys.version)

def create_chat_chain(file_path):
    """
    Create a conversational chain for the chat interface.
    
    Args:
        file_path: Path to the uploaded PDF file
        
    Returns:
        tuple: (status_message, chain, vector_store)
    """
    global vectordb
    
    try:
        # Load the PDF document
        print(f"Loading document: {file_path}")
        loader = PyPDFLoader(file_path)
        docs = loader.load()
        
        if not docs:
            return "Error: No content could be extracted from the PDF.", None, None
            
        print(f"Successfully loaded {len(docs)} pages from the document")

        # Split text into chunks
        print("Splitting documents into chunks...")
        text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=1500,  # Increased chunk size for better context
            chunk_overlap=300,  # Increased overlap for better temporal context
            length_function=len
        )
        split_documents = text_splitter.split_documents(docs)
        print(f"Split into {len(split_documents)} chunks")
        
        # Create embeddings
        print("Creating embeddings...")
        embeddings = HuggingFaceEmbeddings(
            model_name="sentence-transformers/all-mpnet-base-v2"
        )
        
        # Create vector store
        print("Creating vector store...")
        vectordb = FAISS.from_documents(split_documents, embeddings)
        
        # Set up retriever with more context
        retriever = vectordb.as_retriever(
            search_type="mmr",
            search_kwargs={
                "k": 6,  # Increased number of documents to retrieve
                "fetch_k": 20  # Increased fetch size for better context
            }
        )

        # Set up memory with more context
        memory = ConversationBufferMemory(
            memory_key="chat_history",
            return_messages=True,
            output_key="answer",
            input_key="question"
        )

        # Initialize the language model
        print("Initializing language model...")
        llm = ChatOpenAI(
            model_name="gpt-3.5-turbo",
            temperature=0.2,
            max_tokens=1500
        )
        
        # Create the conversational chain with better configuration
        print("Creating conversation chain...")
        from langchain.prompts import PromptTemplate
        from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT
        
        # Create a proper prompt template
        prompt_template = """Use the provided documents to answer the question.
        Be specific and accurate with temporal references.
        If you cannot find the information in the documents, say so clearly.
        
        {context}
        
        Question: {question}
        Answer:"""
        
        PROMPT = PromptTemplate(
            template=prompt_template,
            input_variables=["context", "question"]
        )
        
        # Create the chain with proper configuration
        chain = ConversationalRetrievalChain.from_llm(
            llm=llm,
            retriever=retriever,
            memory=memory,
            return_source_documents=True,
            combine_docs_chain_kwargs={
                "prompt": PROMPT
            }
        )
        
        print("\nChain configuration:")
        print(f"LLM model: gpt-3.5-turbo")  # Hardcoded since we know the model
        print(f"Retriever config: {retriever.search_kwargs}")
        print(f"Memory type: {type(memory).__name__}")
        print(f"Prompt template: {prompt_template}")
        
        print("Chat chain created successfully!")
        return "Document processed successfully! You can now ask questions about the PDF.", chain, vectordb
        
    except Exception as e:
        error_msg = f"Error processing document: {str(e)}"
        print(error_msg)
        import traceback
        traceback.print_exc()
        return error_msg, None, None

def process_user_input(user_message, chat_history):
    """
    Process user input and generate a response using the chat chain.
    
    Args:
        user_message (str): User's message
        chat_history: Current chat history
        
    Returns:
        str: Generated response
    """
    global chat_chain
    if chat_chain is None:
        return "Please upload a PDF file first."
        
    try:
        print(f"Processing question: {user_message}")
        print(f"Current chat history: {len(chat_history)} messages")
        
        # Get response from the chain
        response = chat_chain({"question": user_message, "chat_history": chat_history})
        
        return response["answer"]
        
    except Exception as e:
        import traceback
        print("\nError details:")
        print(f"Error type: {type(e).__name__}")
        print(f"Error message: {str(e)}")
        traceback.print_exc()
        
        if isinstance(e, ValueError):
            error_msg = f"Value error: {str(e)}"
        else:
            error_msg = "An unexpected error occurred. Please try again."
        
        return error_msg

def handle_message(user_message, chat_history):
    """
    Handle incoming messages and update chat history.
    
    Args:
        user_message (str): User's message
        history: Current chat history
        
    Returns:
        tuple: Empty message and updated history
    """
    if not user_message.strip():
        return "", chat_history
    
    # Get response from the chain
    response = process_user_input(user_message, chat_history)
    
    # Update chat history
    chat_history.append((user_message, response))
    
    return "", chat_history

def clear_chat():
    """
    Clear the conversation history.
    
    Returns:
        list: Empty list to clear the chat interface
    """
    global chat_chain
    if chat_chain is not None and hasattr(chat_chain, 'memory') and chat_chain.memory is not None:
        chat_chain.memory.clear()
    return []

def process_uploaded_file(file):
    """
    Process the uploaded PDF file and initialize the chat chain.
    
    Args:
        file: Uploaded file object from Gradio
        
    Returns:
        str: Status message
    """
    global chat_chain, vectordb
    
    if file is None:
        return "No file uploaded. Please upload a PDF file."
    
    try:
        # Get the file path from the Gradio file object
        file_path = file.name
        
        # Validate file type
        if not file_path.lower().endswith('.pdf'):
            return "Error: Only PDF files are supported. Please upload a PDF file."
            
        # Create the chat chain with the uploaded file
        status_msg, new_chain, new_vectordb = create_chat_chain(file_path)
        
        if new_chain is not None and new_vectordb is not None:
            chat_chain = new_chain
            vectordb = new_vectordb
            
        return status_msg
        
    except Exception as e:
        import traceback
        traceback.print_exc()
        return f"Error processing file: {str(e)}"

# Create the Gradio interface
with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown("""
    # RAGBot with Memory
    Upload a PDF file and ask questions about its content.
    """)
    
    # File upload component
    file_output = gr.File(label="Upload a PDF file")
    upload_btn = gr.Button("Process PDF")
    status = gr.Markdown("Please upload a PDF file to begin.")
    
    # Chat interface
    chatbot = gr.Chatbot(height=400, label="Chat History")
    msg = gr.Textbox(placeholder="Type your message here...", label="Your Message")
    
    # Action buttons
    with gr.Row():
        send_btn = gr.Button("Send")
        clear_btn = gr.Button("Clear Conversation")
    
    # Example questions
    examples = [
        "What is this document about?",
        "Can you summarize the key points?",
        "What are the main topics covered?"
    ]
    
    # Add examples
    with gr.Row():
        for example in examples:
            gr.Examples(
                examples=[[example]],
                inputs=msg,
                label=f"Try: {example[:20]}..."
            )
    
    # Event handlers
    upload_btn.click(
        process_uploaded_file,
        inputs=file_output,
        outputs=status
    )
    
    def handle_click(user_message, history):
        return handle_message(user_message, history)
    
    msg.submit(
        handle_click,
        inputs=[msg, chatbot],
        outputs=[msg, chatbot]
    )
    
    send_btn.click(
        handle_click,
        inputs=[msg, chatbot],
        outputs=[msg, chatbot]
    )
    
    clear_btn.click(
        clear_chat,
        outputs=chatbot
    )

# Launch the interface
if __name__ == "__main__":
    print("Starting RAGBot application...")
    demo.launch(share=False)