cd /news/artificial-intelligence/your-first-rag-application-for-a-pdf… · home › topics › artificial-intelligence › article
[ARTICLE · art-158610] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

Your First RAG Application for a PDF Summay

A developer published a hands-on walkthrough for building a retrieval-augmented generation (RAG) PDF summarizer using Streamlit, LangChain, Chroma, and OpenAI-compatible chat and embedding models. The pipeline extracts text with pdfminer, splits it into 1,000-character chunks with 200-character overlap, indexes them in a persistent Chroma collection, and runs a RetrievalQA chain that returns source documents alongside the generated summary. The code includes guards for empty or scanned PDFs and cleans up temporary files after processing.

by read2 min views1 publishedOct 27, 2026
import os
import tempfile
from pathlib import Path

import streamlit as st
import httpx
from pdfminer.high_level import extract_text

from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_classic.chains import RetrievalQA


st.set_page_config(page_title="RAG PDF Summarizer")
st.title("RAG-powered PDF Summarizer")


API_KEY = "Your API Key"
BASE_URL = "https://yourbaseurl.com"

if not API_KEY:
    st.error("GENAI_API_KEY is not configured.")
    st.stop()

client = httpx.Client(timeout=120.0, verify=True)

llm = ChatOpenAI(
    base_url=BASE_URL,
    model="azure_ai/genailab-maas-DeepSeek-V3-0324",
    api_key=API_KEY,
    http_client=client,
)

embedding_model = OpenAIEmbeddings(
    base_url=BASE_URL,
    model="azure/genailab-maas-text-embedding-3-large",
    api_key=API_KEY,
    http_client=client,
)


uploaded_file = st.file_up(
    "Upload a PDF",
    type=["pdf"],
)

if uploaded_file is not None:
    temp_path = None

    try:
        with tempfile.NamedTemporaryFile(
            delete=False,
            suffix=".pdf",
        ) as temp_file:
            temp_file.write(uploaded_file.getvalue())
            temp_path = temp_file.name

        with st.spinner("Extracting PDF text..."):
            raw_text = extract_text(temp_path)

        if not raw_text or not raw_text.strip():
            st.error(
                "No readable text found. "
                "If this is a scanned PDF, OCR is required."
            )
            st.stop()

        text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=1000,
            chunk_overlap=200,
        )

        chunks = text_splitter.split_text(raw_text)

        if not chunks:
            st.error("No text chunks were generated.")
            st.stop()

        st.write(f"Created {len(chunks)} text chunks.")

        chroma_dir = Path.home() / "rag_chroma_data"
        chroma_dir.mkdir(parents=True, exist_ok=True)

        with st.spinner("Indexing PDF..."):
            vectordb = Chroma.from_texts(
                texts=chunks,
                embedding=embedding_model,
                persist_directory=str(chroma_dir),
                collection_name="pdf_collection",
            )

        retriever = vectordb.as_retriever(
            search_type="similarity",
            search_kwargs={"k": min(5, len(chunks))},
        )

        rag_chain = RetrievalQA.from_chain_type(
            llm=llm,
            chain_type="stuff",
            retriever=retriever,
            return_source_documents=True,
        )

        summary_prompt = (
            "Summarize the uploaded document using the retrieved context. "
            "Explain the main topics, key findings, important facts, "
            "and conclusions. Do not invent unsupported information."
        )

        with st.spinner("Generating summary..."):
            result = rag_chain.invoke({"query": summary_prompt})

        st.subheader("Document Summary")
        st.write(result["result"])

        with st.expander("View source documents"):
            for i, doc in enumerate(
                result["source_documents"],
                start=1,
            ):
                st.markdown(f"**Source {i}**")
                st.write(doc.page_content)

    except Exception as exc:
        st.error(f"Processing failed: {exc}")

    finally:
        if temp_path and os.path.exists(temp_path):
            os.remove(temp_path)
── more in #artificial-intelligence 4 stories · sorted by recency
── more on @streamlit 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/your-first-rag-appli…] indexed:0 read:2min 2026-10-27 · —