rag-doc-qa / app.py
ShubhamAC's picture
Update app.py
1860fba verified
Raw
History Blame Contribute Delete
5.47 kB
"""
app.py
Gradio UI for the RAG Document Q&A system.
"""
import os
import shutil
import tempfile
import logging
import gradio as gr
from rag_pipeline import RAGPipeline
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
pipeline = RAGPipeline()
# ──────────────────────────────────────────────
# Handlers
# ──────────────────────────────────────────────
def handle_upload(file):
if file is None:
return "⚠️ No file uploaded.", gr.update(interactive=False)
try:
ext = os.path.splitext(file.name)[1].lower()
tmp_path = tempfile.mktemp(suffix=ext)
shutil.copy(file.name, tmp_path)
stats = pipeline.ingest_document(tmp_path)
status = (
f"βœ… **Document ready!**\n\n"
f"- πŸ“„ File: `{stats['document']}`\n"
f"- 🧩 Chunks: `{stats['chunks']}`\n"
f"- πŸ“ Embedding dim: `{stats['embedding_dim']}`\n"
f"- ⚑ Ingestion time: `{stats['ingestion_time_s']}s`\n\n"
f"You can now ask questions below."
)
return status, gr.update(interactive=True)
except Exception as e:
logger.error(f"Upload error: {e}")
return f"❌ Error processing document: {str(e)}", gr.update(interactive=False)
def handle_query(question, history):
if not pipeline.is_ready:
history.append((question, "⚠️ Please upload a document first."))
return history, "", ""
if not question.strip():
return history, "", ""
try:
result = pipeline.query(question)
answer = result["answer"]
latency = result["latency_s"]
# βœ… FIXED: use rank instead of score
sources_md = "### πŸ“š Retrieved Sources\n\n"
for src in result["sources"]:
rank = src["rank"]
excerpt = src["chunk"][:300] + ("..." if len(src["chunk"]) > 300 else "")
sources_md += f"**Source {rank}**\n\n> {excerpt}\n\n---\n\n"
history.append((question, answer))
return history, sources_md, f"⚑ Response time: {latency}s"
except Exception as e:
logger.error(f"Query error: {e}")
history.append((question, f"❌ Error: {str(e)}"))
return history, "", ""
def clear_all():
return [], "", ""
# ──────────────────────────────────────────────
# UI
# ──────────────────────────────────────────────
with gr.Blocks(
title="RAG Document Q&A",
theme=gr.themes.Soft(primary_hue="blue"),
css="""
.title { text-align: center; margin-bottom: 8px; }
.subtitle { text-align: center; color: #64748b; margin-bottom: 24px; }
footer { display: none !important; }
"""
) as demo:
gr.Markdown("# πŸ“„ RAG Document Q&A", elem_classes="title")
gr.Markdown(
"Upload a PDF or TXT document, then ask questions. "
"Answers are grounded in your document β€” not hallucinated.",
elem_classes="subtitle"
)
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### πŸ“ Upload Document")
file_input = gr.File(
label="Upload PDF or TXT (max 10 MB)",
file_types=[".pdf", ".txt"],
)
upload_status = gr.Markdown("_No document loaded yet._")
with gr.Column(scale=2):
gr.Markdown("### πŸ’¬ Ask a Question")
chatbot = gr.Chatbot(height=380, label="Conversation")
with gr.Row():
question_box = gr.Textbox(
placeholder="e.g. What is the main topic of this document?",
label="Your question",
scale=4,
interactive=False,
)
submit_btn = gr.Button("Ask πŸš€", variant="primary", scale=1)
latency_display = gr.Markdown("")
clear_btn = gr.Button("πŸ—‘οΈ Clear conversation", variant="secondary")
with gr.Accordion("πŸ“š View Retrieved Sources", open=False):
sources_display = gr.Markdown("_Ask a question to see retrieved sources._")
gr.Markdown("### πŸ’‘ Example Questions")
gr.Examples(
examples=[
["What is the main topic of this document?"],
["Summarize the key points."],
["What conclusions are drawn?"],
["What data or evidence is mentioned?"],
],
inputs=question_box,
)
# Events
file_input.change(
fn=handle_upload,
inputs=file_input,
outputs=[upload_status, question_box],
)
submit_btn.click(
fn=handle_query,
inputs=[question_box, chatbot],
outputs=[chatbot, sources_display, latency_display],
)
question_box.submit(
fn=handle_query,
inputs=[question_box, chatbot],
outputs=[chatbot, sources_display, latency_display],
)
clear_btn.click(
fn=clear_all,
outputs=[chatbot, sources_display, latency_display],
)
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=True,
)