{"slug": "your-first-rag-application-for-a-pdf-summay", "title": "Your First RAG Application for a PDF Summay", "summary": "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.", "body_md": "```\nimport os\nimport tempfile\nfrom pathlib import Path\n\nimport streamlit as st\nimport httpx\nfrom pdfminer.high_level import extract_text\n\nfrom langchain_text_splitters import RecursiveCharacterTextSplitter\nfrom langchain_openai import ChatOpenAI, OpenAIEmbeddings\nfrom langchain_community.vectorstores import Chroma\nfrom langchain_classic.chains import RetrievalQA\n\n# Streamlit configuration\n\nst.set_page_config(page_title=\"RAG PDF Summarizer\")\nst.title(\"RAG-powered PDF Summarizer\")\n\n# API configuration\n\nAPI_KEY = \"Your API Key\"\nBASE_URL = \"https://yourbaseurl.com\"\n\nif not API_KEY:\n    st.error(\"GENAI_API_KEY is not configured.\")\n    st.stop()\n\n# Keep TLS certificate verification enabled.\nclient = httpx.Client(timeout=120.0, verify=True)\n\nllm = ChatOpenAI(\n    base_url=BASE_URL,\n    model=\"azure_ai/genailab-maas-DeepSeek-V3-0324\",\n    api_key=API_KEY,\n    http_client=client,\n)\n\nembedding_model = OpenAIEmbeddings(\n    base_url=BASE_URL,\n    model=\"azure/genailab-maas-text-embedding-3-large\",\n    api_key=API_KEY,\n    http_client=client,\n)\n\n# PDF upload\n\nuploaded_file = st.file_uploader(\n    \"Upload a PDF\",\n    type=[\"pdf\"],\n)\n\nif uploaded_file is not None:\n    temp_path = None\n\n    try:\n        # Step 1: Save the uploaded PDF temporarily\n        with tempfile.NamedTemporaryFile(\n            delete=False,\n            suffix=\".pdf\",\n        ) as temp_file:\n            temp_file.write(uploaded_file.getvalue())\n            temp_path = temp_file.name\n\n        # Step 2: Extract text\n        with st.spinner(\"Extracting PDF text...\"):\n            raw_text = extract_text(temp_path)\n\n        if not raw_text or not raw_text.strip():\n            st.error(\n                \"No readable text found. \"\n                \"If this is a scanned PDF, OCR is required.\"\n            )\n            st.stop()\n\n        # Step 3: Split text into chunks\n        text_splitter = RecursiveCharacterTextSplitter(\n            chunk_size=1000,\n            chunk_overlap=200,\n        )\n\n        chunks = text_splitter.split_text(raw_text)\n\n        if not chunks:\n            st.error(\"No text chunks were generated.\")\n            st.stop()\n\n        st.write(f\"Created {len(chunks)} text chunks.\")\n\n        # Step 4: Create the Chroma vector database\n        chroma_dir = Path.home() / \"rag_chroma_data\"\n        chroma_dir.mkdir(parents=True, exist_ok=True)\n\n        with st.spinner(\"Indexing PDF...\"):\n            vectordb = Chroma.from_texts(\n                texts=chunks,\n                embedding=embedding_model,\n                persist_directory=str(chroma_dir),\n                collection_name=\"pdf_collection\",\n            )\n\n        # Step 5: Create retriever\n        retriever = vectordb.as_retriever(\n            search_type=\"similarity\",\n            search_kwargs={\"k\": min(5, len(chunks))},\n        )\n\n        # Step 6: Create the RAG chain\n        rag_chain = RetrievalQA.from_chain_type(\n            llm=llm,\n            chain_type=\"stuff\",\n            retriever=retriever,\n            return_source_documents=True,\n        )\n\n        # Step 7: Generate the summary\n        summary_prompt = (\n            \"Summarize the uploaded document using the retrieved context. \"\n            \"Explain the main topics, key findings, important facts, \"\n            \"and conclusions. Do not invent unsupported information.\"\n        )\n\n        with st.spinner(\"Generating summary...\"):\n            result = rag_chain.invoke({\"query\": summary_prompt})\n\n        # Step 8: Display results\n        st.subheader(\"Document Summary\")\n        st.write(result[\"result\"])\n\n        with st.expander(\"View source documents\"):\n            for i, doc in enumerate(\n                result[\"source_documents\"],\n                start=1,\n            ):\n                st.markdown(f\"**Source {i}**\")\n                st.write(doc.page_content)\n\n    except Exception as exc:\n        st.error(f\"Processing failed: {exc}\")\n\n    finally:\n        if temp_path and os.path.exists(temp_path):\n            os.remove(temp_path)\n```", "url": "https://wpnews.pro/news/your-first-rag-application-for-a-pdf-summay", "canonical_source": "https://dev.to/vjonnagadla/your-first-rag-application-for-a-pdf-summay-2okf", "published_at": "2026-10-27 09:37:29+00:00", "updated_at": "2026-10-27 09:42:56.398287+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "generative-ai", "ai-tools", "ai-agents"], "entities": ["Streamlit", "LangChain", "Chroma", "OpenAI", "pdfminer", "DeepSeek-V3"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/your-first-rag-application-for-a-pdf-summay", "markdown": "https://wpnews.pro/news/your-first-rag-application-for-a-pdf-summay.md", "text": "https://wpnews.pro/news/your-first-rag-application-for-a-pdf-summay.txt", "jsonld": "https://wpnews.pro/news/your-first-rag-application-for-a-pdf-summay.jsonld"}}