GeekHub Learn
Module
Lesson 9.66 of 8 in this module2 min read Module 9: Building a PDF Chatbot (RAG Project)

Streamlit UI: upload, chat, citations

Wiring up the UI is what turns code into a product anyone can use. Two hours and you have a real app.

You wrote the engine. Now you bolt on the steering wheel, the seat, the dashboard.

UI pieces:

  • Sidebar PDF uploader (calls ingest)
  • Chat input and history
  • Streaming responses
  • Source citations expander
import streamlit as st
from rag import index_pdf, answer

st.title("PDF Chatbot")

with st.sidebar:
    uploaded = st.file_uploader("Upload PDF", type=["pdf"])
    if uploaded:
        path = f"data/{uploaded.name}"
        with open(path, "wb") as f:
            f.write(uploaded.read())
        n = index_pdf(path)
        st.success(f"Indexed {n} chunks from {uploaded.name}")

if "messages" not in st.session_state:
    st.session_state.messages = []

for msg in st.session_state.messages:
    with st.chat_message(msg["role"]):
        st.markdown(msg["content"])

if prompt := st.chat_input("Ask about your PDFs"):
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)

    with st.chat_message("assistant"):
        placeholder = st.empty()
        text = ""
        for delta in answer(prompt):
            text += delta
            placeholder.markdown(text + "_")
        placeholder.markdown(text)
        st.session_state.messages.append({"role": "assistant", "content": text})

That is the whole app.

Visualize it

Annotated screenshot of the final UI with arrows pointing to uploader, chat input, chat history, and citations.

Try it now

Run it. Upload your own PDF. Ask 3 questions. Take a screenshot.

Hands-on lab

Build the UI. Upload a PDF of your choice (your resume, a textbook chapter). Ask 5 questions. Share the screenshot in the GeekHub community.

Try it now

Why is the placeholder pattern needed for streaming?

Common mistakes

  • Forgetting os.makedirs("data", exist_ok=True)
  • Not showing ingest progress for large PDFs
  • Allowing huge file uploads (cap with Streamlit config)

Debugging tip

If users complain "it does not see my upload", check that ingest finished before they asked a question. Add an indicator.

Challenge

Add a "Clear all PDFs" button that wipes Chroma and clears uploads.

Where this shows up

  • Document Q&A products
  • Internal knowledge bots
  • Education tools

From the field

A clean, focused UI for a single use case beats a feature-rich messy app every time. Resist scope creep.

Recap

Sidebar upload, chat input, streaming, citations. The whole app is one screen.


Quick recall

3 prompts · think before you flip

Prompt 1 of 3

Why use `st.session_state` here?

Quiz time

1 question · tap an answer to check it

  1. 1. The sidebar uploader's main job is to

Finished lesson 9.6?

Mark complete to update your module progress and unlock the streak.

Loading