nikhmr1235 commited on
Commit
1f44a86
·
verified ·
1 Parent(s): cfdf352

Application file with Gradio UI to upload PDF and chatbot interface for Q&A on the PDF document

Browse files

-- User Interface (Gradio): The interface will be an "all-in-one" single-page layout.
- It will feature a clear file upload area for PDF documents at the top.
- Below the upload area, a chat interface will be present.
- the chat interface will be "disabled by default". It will only become active and usable after a PDF has been successfully uploaded and processed.
- similarly PDF upload interface will be disabled after chat interface is enabled

Files changed (1) hide show
  1. app.py +177 -0
app.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import uuid
4
+ import shutil
5
+ import PyMuPDF
6
+ from langchain_community.vectorstores import Chroma
7
+ from langchain_google_genai import ChatGoogleGenerativeAI, GoogleGenerativeAIEmbeddings
8
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
9
+ from langchain.prompts import PromptTemplate
10
+ from langchain_core.runnables import RunnablePassthrough
11
+ from langchain_core.output_parsers import StrOutputParser
12
+
13
+ import tempfile
14
+
15
+ # Constants
16
+ LLM_MODEL = "gemini-1.5-flash"
17
+ EMBEDDING_MODEL = "BAAI/bge-large-en-v1.5"
18
+ CHROMA_DB_PATH = tempfile.gettempdir() + "/chroma_db"
19
+
20
+ # Global state to hold session data
21
+ class SessionState:
22
+ def __init__(self):
23
+ self.session_id = str(uuid.uuid4())
24
+ self.db = None
25
+ self.vector_store_path = os.path.join(CHROMA_DB_PATH, self.session_id)
26
+
27
+ def is_db_ready(self):
28
+ return self.db is not None
29
+
30
+ # Gradio components to be enabled/disabled
31
+ CHAT_COMPONENTS = None
32
+ FILE_UPLOAD_COMPONENTS = None
33
+
34
+ def initialize_components(file_upload_input, chat_input, chatbot):
35
+ global CHAT_COMPONENTS, FILE_UPLOAD_COMPONENTS
36
+ CHAT_COMPONENTS = [chat_input, chatbot]
37
+ FILE_UPLOAD_COMPONENTS = [file_upload_input]
38
+
39
+ # Helper function to generate a new session state
40
+ def new_session():
41
+ return SessionState()
42
+
43
+ # Function to handle PDF upload and ingestion
44
+ def process_pdf(pdf_file, state):
45
+ try:
46
+ if state.is_db_ready():
47
+ return (
48
+ f"A PDF has already been processed. Please refresh the page to upload a new one.",
49
+ [],
50
+ gr.ChatInterface(disabled=False),
51
+ gr.File(disabled=True)
52
+ )
53
+
54
+ # Create a new session and directory for the user
55
+ state = new_session()
56
+ if not os.path.exists(state.vector_store_path):
57
+ os.makedirs(state.vector_store_path)
58
+
59
+ # Extract text from the PDF
60
+ doc = PyMuPDF.open(pdf_file.name)
61
+ text = ""
62
+ for page in doc:
63
+ text += page.get_text()
64
+ doc.close()
65
+
66
+ # Split text into chunks
67
+ text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
68
+ docs = text_splitter.create_documents([text])
69
+
70
+ # Create a ChromaDB vector store from the documents
71
+ embeddings = GoogleGenerativeAIEmbeddings(model=EMBEDDING_MODEL)
72
+ state.db = Chroma.from_documents(
73
+ documents=docs,
74
+ embedding=embeddings,
75
+ persist_directory=state.vector_store_path
76
+ )
77
+
78
+ gr.Info("PDF processed successfully! You can now ask questions about the document.")
79
+ return (
80
+ "",
81
+ [["", "PDF processed successfully! You can now ask questions."]],
82
+ gr.ChatInterface(disabled=False),
83
+ gr.File(disabled=True)
84
+ )
85
+ except Exception as e:
86
+ # Clean up the directory in case of an error
87
+ if os.path.exists(state.vector_store_path):
88
+ shutil.rmtree(state.vector_store_path)
89
+ gr.Error(f"An error occurred: {str(e)}")
90
+ return (
91
+ "",
92
+ [["", f"An error occurred during processing: {str(e)}"]],
93
+ gr.ChatInterface(disabled=True),
94
+ gr.File(disabled=False)
95
+ )
96
+
97
+ # Function to handle user queries
98
+ def chat_with_pdf(message, history, state):
99
+ if not state.is_db_ready():
100
+ yield "Please upload a PDF first to begin the conversation."
101
+ return
102
+
103
+ # Use the ChromaDB instance from the session state
104
+ retriever = state.db.as_retriever()
105
+
106
+ # Set up the RAG chain
107
+ llm = ChatGoogleGenerativeAI(model=LLM_MODEL, temperature=0.7)
108
+
109
+ prompt_template = PromptTemplate(
110
+ template="""
111
+ You are a helpful assistant for a PDF document.
112
+ Answer the user's question based on the following context.
113
+ If you don't know the answer, just say that you don't know, don't try to make up an answer.
114
+ ----------------
115
+ Context: {context}
116
+ Question: {question}
117
+ """,
118
+ input_variables=["context", "question"],
119
+ )
120
+
121
+ rag_chain = (
122
+ {"context": retriever, "question": RunnablePassthrough()}
123
+ | prompt_template
124
+ | llm
125
+ | StrOutputParser()
126
+ )
127
+
128
+ response = rag_chain.invoke(message)
129
+ yield response
130
+
131
+ # Gradio Interface
132
+ with gr.Blocks(title="PDF Chatbot") as demo:
133
+ state = gr.State(new_session)
134
+
135
+ gr.Markdown(
136
+ """
137
+ # PDF Chatbot
138
+ Upload a PDF to start a conversation with your document.
139
+ The chat interface will become active after the file is processed.
140
+ """
141
+ )
142
+
143
+ with gr.Row():
144
+ file_upload_input = gr.File(
145
+ file_types=[".pdf"],
146
+ label="Upload your PDF document",
147
+ interactive=True
148
+ )
149
+
150
+ chatbot = gr.Chatbot(label="Chat History", placeholder="Upload a document to start a conversation...")
151
+ chat_input = gr.Textbox(
152
+ placeholder="Type your question here...",
153
+ scale=7
154
+ )
155
+
156
+ chat_interface = gr.ChatInterface(
157
+ fn=chat_with_pdf,
158
+ textbox=chat_input,
159
+ chatbot=chatbot,
160
+ examples=["What is the main topic of the document?", "Summarize the key findings.", "Who are the authors?"],
161
+ title="Chat Interface",
162
+ theme="soft",
163
+ # Chat is disabled until a file is processed
164
+ disabled=True
165
+ )
166
+
167
+ # Store components in global variables for easy access
168
+ initialize_components(file_upload_input, chat_input, chatbot)
169
+
170
+ # Event handlers
171
+ file_upload_input.upload(
172
+ fn=process_pdf,
173
+ inputs=[file_upload_input, state],
174
+ outputs=[file_upload_input, chatbot, chat_interface, file_upload_input]
175
+ )
176
+
177
+ demo.launch()