Team Ai
Apppublic

Inzeera/Multi_Document_Summarizer_Plus_QA_Bot

sourceHugging Faceupdated 23d agoView on Hugging Face
0likes
app.py534 linesDownload Raw Back to root
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)