Inzeera/Multi_Document_Summarizer_Plus_QA_Bot
0
1import os
2import streamlit as st
3
4from config.settings import GROQ_API_KEY
5
6from loaders.pdf_loader import load_pdf
7from loaders.docx_loader import load_docx
8from loaders.excel_loader import load_excel
9
10from rag.llm import get_llm
11from rag.vectordb import create_vectordb
12from rag.qa_chain import build_qa_chain, ask_question
13from rag.summarizer import summarize_docs
14
15from utils.pdf_export import generate_summary_pdf
16
17from langchain_text_splitters import RecursiveCharacterTextSplitter
18
19
20st.set_page_config(
21 page_title="Document Summarizer & QA Bot",
22 layout="wide"
23)
24
25if not GROQ_API_KEY:
26 st.error("GROQ_API_KEY not found in .env file")
27 st.stop()
28
29
30st.markdown("""
31<style>
32
33/* ---------------- Background ---------------- */
34
35.stApp{
36 background: linear-gradient(
37 135deg,
38 #0f172a,
39 #1e293b,
40 #334155
41 );
42}
43
44
45/* ---------------- Hero ---------------- */
46
47.main-title{
48 text-align:center;
49 font-size:48px;
50 font-weight:700;
51 color:white;
52}
53
54.sub-title{
55 text-align:center;
56 font-size:18px;
57 color:#cbd5e1;
58 margin-top:10px;
59}
60
61
62/* ---------------- Glass Card ---------------- */
63
64.glass-card{
65
66 background: rgba(
67 255,
68 255,
69 255,
70 0.08
71 );
72
73 backdrop-filter: blur(12px);
74 -webkit-backdrop-filter: blur(12px);
75
76 border: 1px solid rgba(
77 255,
78 255,
79 255,
80 0.15
81 );
82
83 border-radius:20px;
84
85 padding:25px;
86
87 margin-bottom:20px;
88
89 box-shadow:
90 0 8px 32px rgba(
91 0,
92 0,
93 0,
94 0.25
95 );
96}
97
98
99/* ---------------- Tabs ---------------- */
100
101.stTabs [data-baseweb="tab-list"]{
102
103 gap:10px;
104
105}
106
107.stTabs [data-baseweb="tab"]{
108
109 height:55px;
110
111 border-radius:12px;
112
113 background: rgba(
114 255,
115 255,
116 255,
117 0.08
118 );
119
120 color:white;
121}
122
123.stTabs [aria-selected="true"]{
124
125 background: rgba(
126 255,
127 255,
128 255,
129 0.18
130 );
131}
132
133
134/* ---------------- Buttons ---------------- */
135
136.stButton > button{
137
138 width:100%;
139
140 height:50px;
141
142 border-radius:12px;
143
144 font-weight:600;
145}
146
147
148/* ---------------- File Uploader ---------------- */
149
150section[data-testid="stFileUploader"]{
151
152 background: rgba(
153 255,
154 255,
155 255,
156 0.05
157 );
158
159 padding:15px;
160
161 border-radius:15px;
162}
163
164
165/* ---------------- Metrics ---------------- */
166
167[data-testid="metric-container"]{
168
169 background: rgba(
170 255,
171 255,
172 255,
173 0.08
174 );
175
176 border: 1px solid rgba(
177 255,
178 255,
179 255,
180 0.15
181 );
182
183 padding:15px;
184
185 border-radius:15px;
186}
187
188
189/* ---------------- Sidebar ---------------- */
190
191[data-testid="stSidebar"]{
192
193 background: rgba(
194 15,
195 23,
196 42,
197 0.95
198 );
199}
200
201</style>
202""", unsafe_allow_html=True)
203
204
205
206
207with st.sidebar:
208 st.title("RAG Control Panel")
209
210 st.markdown("---")
211
212 summary_type = st.selectbox(
213 "Summary Level",
214 [
215 "Short",
216 "Medium",
217 "Detailed"
218 ]
219 )
220
221 chunk_size = st.slider(
222 "Chunk Size",
223 min_value=500,
224 max_value=1500,
225 value=800,
226 step=100
227 )
228
229 st.markdown("---")
230
231 if st.button("Clear Session"):
232 st.cache_resource.clear()
233 st.session_state.clear()
234 st.rerun()
235
236# ---------------------------------------------------
237# LOAD LLM
238# ---------------------------------------------------
239
240with st.spinner("Loading AI Models..."):
241 llm = get_llm()
242
243
244# ---------------------------------------------------
245# HERO SECTION
246# ---------------------------------------------------
247
248st.markdown("""
249<div class="glass-card">
250
251<div class="main-title">
252๐ Document Summarizer & QA Bot
253</div>
254
255<div class="sub-title">
256Upload PDF, DOCX, and Excel documents.
257Generate summaries and ask intelligent questions using RAG.
258</div>
259
260</div>
261""", unsafe_allow_html=True)
262
263
264# ---------------------------------------------------
265# CREATE TABS
266# ---------------------------------------------------
267
268tab1, tab2, tab3 = st.tabs([
269 "๐ Upload Documents",
270 "๐ Generate Summary",
271 "โ Ask Questions"
272])
273
274# UPLOAD TAB
275with tab1:
276
277 uploaded_files = st.file_uploader(
278 "Upload PDF, DOCX, XLS or XLSX Files",
279 type=["pdf", "docx", "xls", "xlsx"],
280 accept_multiple_files=True
281)
282
283if uploaded_files:
284
285 current_signature = []
286
287 for file in uploaded_files:
288 current_signature.append(
289 (
290 file.name,
291 len(file.getvalue())
292 )
293 )
294
295 current_signature = str(sorted(current_signature))
296 previous_signature = st.session_state.get("file_signature")
297
298 if current_signature != previous_signature:
299 st.session_state.pop("summary",None)
300 st.session_state.pop("chunks",None)
301 st.session_state.pop("vectordb",None)
302 st.session_state.pop("qa_chain",None)
303
304 os.makedirs("temp_docs",exist_ok=True)
305
306 all_docs = []
307
308 with st.spinner("Reading uploaded files..."):
309 for file in uploaded_files:
310 file_path = os.path.join("temp_docs",file.name)
311
312 with open(file_path, "wb") as f:
313 f.write(file.getbuffer())
314
315 if file.name.endswith(".pdf"):
316 all_docs.extend(load_pdf(file_path))
317 elif file.name.endswith(".docx"):
318 all_docs.extend(load_docx(file_path))
319 else:
320 all_docs.extend(load_excel(file_path))
321
322 splitter = RecursiveCharacterTextSplitter(
323 chunk_size=chunk_size,
324 chunk_overlap=200
325 )
326
327 chunks = splitter.split_documents(all_docs)
328
329 with st.spinner("Creating vector database..."):
330 vectordb = create_vectordb(chunks)
331
332 with st.spinner("Initializing QA engine..."):
333 qa_chain = build_qa_chain(llm,vectordb)
334
335 st.session_state["chunks"] = chunks
336 st.session_state["vectordb"] = vectordb
337 st.session_state[ "qa_chain"] = qa_chain
338 st.session_state["file_signature"] = current_signature
339
340 chunks = st.session_state[ "chunks"]
341 qa_chain = st.session_state["qa_chain"]
342
343 st.success("Documents processed successfully.")
344# ---------------------------------------------------
345# SUMMARY TAB
346# ---------------------------------------------------
347
348with tab2:
349
350 st.markdown(
351 """
352 <h3 style="color:white;">
353 Generate Document Summary
354 </h3>
355 """,
356 unsafe_allow_html=True
357 )
358
359 if "chunks" not in st.session_state:
360
361 st.warning("Please upload documents first.")
362
363 else:
364
365 chunks = st.session_state["chunks"]
366
367 summary_map = {
368
369 "Short":
370 "Provide a concise executive summary.",
371
372 "Medium":
373 "Provide a structured paragraph-wise summary.",
374
375 "Detailed":
376 """
377 Provide a detailed summary
378 with key insights,
379 important findings,
380 and major conclusions.
381 """
382 }
383
384 if st.button("Generate Summary",key="summary_btn"):
385 summary = summarize_docs(llm,
386 st.session_state["chunks"],
387 summary_map[summary_type])
388
389 st.session_state["summary"] = summary
390
391
392 # -----------------------------
393 # DISPLAY SUMMARY
394 # -----------------------------
395
396 if "summary" in st.session_state:
397
398 st.markdown(
399 """
400 <div class="glass-card">
401 """,
402 unsafe_allow_html=True
403 )
404
405 st.subheader("Generated Summary")
406
407 st.write(
408 st.session_state["summary"])
409
410 st.markdown(
411 "</div>",
412 unsafe_allow_html=True
413 )
414
415 # -------------------------
416 # DOWNLOADS
417 # -------------------------
418
419 st.markdown(
420 "### Download Summary"
421 )
422
423 col1, col2 = st.columns(2)
424
425 with col1:
426 st.download_button(
427 label="Download TXT",
428 data=st.session_state["summary"],
429 file_name="document_summary.txt",
430 mime="text/plain")
431
432 with col2:
433 pdf_path = ( generate_summary_pdf(st.session_state["summary"]))
434
435 with open(pdf_path,"rb") as pdf:
436 st.download_button(
437 label="Download PDF",
438 data=pdf,
439 file_name="document_summary.pdf",
440 mime="application/pdf")
441
442# ---------------------------------------------------
443# QA TAB
444# ---------------------------------------------------
445
446with tab3:
447
448 st.markdown(
449 """
450 <div class="glass-card">
451 <h3 style="color:white;">
452 Ask Questions
453 </h3>
454 </div>
455 """,
456 unsafe_allow_html=True
457 )
458
459 if "qa_chain" not in st.session_state:
460 st.warning("Please upload documents first.")
461 st.stop()
462
463 qa_chain = st.session_state["qa_chain"]
464
465 question = st.text_area(
466 "Enter your question",
467 height=120,
468 placeholder="Example: What is the main objective of the document?"
469 )
470
471 if st.button("Get Answer", key="qa_btn"):
472 if question.strip():
473 with st.spinner("Searching documents..."):
474 answer, sources = ask_question(qa_chain, question)
475
476 st.markdown(
477 """
478 <div class="glass-card">
479 """,
480 unsafe_allow_html=True
481 )
482
483 st.subheader("Answer")
484
485 st.write(answer)
486
487 st.markdown(
488 "</div>",
489 unsafe_allow_html=True
490 )
491
492 st.markdown(
493 """
494 <div class="glass-card">
495 """,
496 unsafe_allow_html=True
497 )
498
499 st.subheader("Source References")
500
501 for src in sources:
502 st.write("โข",src)
503
504 st.markdown(
505 "</div>",
506 unsafe_allow_html=True
507 )
508
509 else:
510 st.warning("Please enter a question.")
511
512
513# ---------------------------------------------------
514# FOOTER
515# ---------------------------------------------------
516
517st.markdown(
518"""
519<br><br>
520
521<div style="
522text-align:center;
523color:#94a3b8;
524font-size:14px;
525">
526
527Document Summarizer & QA Bot<br>
528Built with Streamlit, LangChain,
529ChromaDB and Groq
530
531</div>
532""",
533unsafe_allow_html=True
534)