home
diamond Go Premium
Data Engineering Path  ·  Data & AI

Capstone 1: Enterprise PDF Chatbot with RAG

+-----------------------------------------------------------------------------------+
|                           PROJECT 1 ARCHITECTURE                                  |
+-----------------------------------------------------------------------------------+
|  PDF Upload -> PyMuPDF Text & Table Extraction -> Recursive Semantic Chunking     |
|                                                          |                        |
|                                                          v                        |
|  Query Engine <- Cosine Reranking <- Hybrid Search <- ChromaDB Vector Store       |
|       |                                                                           |
|       v                                                                           |
|  Streaming Answer with Exact Citations & Page References (FastAPI + Streamlit)    |
+-----------------------------------------------------------------------------------+

Objective

Build a production document Q&A assistant capable of ingesting multi-page complex enterprise PDFs (contracts, architecture specs, financial reports) and providing answers with verified page citations.


Complete Implementation

import os
import fitz # PyMuPDF
import chromadb
from chromadb.utils import embedding_functions
from openai import OpenAI

client = OpenAI()

# 1. Extract and Chunk PDF with Page Metadata
def extract_pdf_chunks(pdf_path: str, chunk_size: int = 500, overlap: int = 50) -> list[dict]:
    doc = fitz.open(pdf_path)
    chunks = []

    for page_num in range(len(doc)):
        page = doc[page_num]
        text = page.get_text("text").strip()
        if not text:
            continue

        words = text.split()
        for i in range(0, len(words), chunk_size - overlap):
            chunk_words = words[i:i + chunk_size]
            chunk_text = " ".join(chunk_words)
            chunks.append({
                "text": chunk_text,
                "metadata": {
                    "source": os.path.basename(pdf_path),
                    "page": page_num + 1,
                    "chunk_id": f"{page_num+1}_{i}"
                }
            })
    return chunks

# 2. Ingest into ChromaDB
def ingest_chunks_to_chroma(chunks: list[dict], collection_name: str = "enterprise_docs"):
    chroma_client = chromadb.Client()
    openai_ef = embedding_functions.OpenAIEmbeddingFunction(
        api_key=os.environ.get("OPENAI_API_KEY"),
        model_name="text-embedding-3-small"
    )
    collection = chroma_client.get_or_create_collection(
        name=collection_name,
        embedding_function=openai_ef
    )

    collection.add(
        documents=[c["text"] for c in chunks],
        metadatas=[c["metadata"] for c in chunks],
        ids=[f"doc_{idx}" for idx in range(len(chunks))]
    )
    return collection

# 3. RAG Generation with Citations
def query_rag_engine(collection, question: str) -> str:
    results = collection.query(query_texts=[question], n_results=3)
    retrieved_texts = results["documents"][0]
    retrieved_meta = results["metadatas"][0]

    context_str = ""
    for text, meta in zip(retrieved_texts, retrieved_meta):
        context_str += f"
[Document: {meta['source']} | Page: {meta['page']}]
{text}
"

    prompt = f"""
Answer the user's question using ONLY the provided context snippets.
Always cite the exact Page numbers supporting your answer.

CONTEXT:
{context_str}

QUESTION:
{question}
"""
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.1
    )
    return response.choices[0].message.content
Find this content helpful? ☕ Buy me a coffee

Entity Details

Create New Item

help

Submit Technical Query

Have a question or run into an issue? Describe it below, upload an optional screenshot, and our engineering team will answer it!

image Attach image (optional)

Submit Feedback

build Free Developer Utility Free Tool
gavel

Privacy & Legal Disclaimer

1. Client-Side Browser Processing

All utility tools on DeepEngineerHub (including Image to PDF, Text Formatters, JSON Converters, and Encryptors) execute 100% locally within your client browser using WebAssembly and JavaScript. No uploaded images, text, or documents are transmitted, collected, or stored on remote servers.

2. Limitation of Liability ("As-Is" Provision)

Tools and services are provided free of charge for convenience and educational purposes "as-is" without warranties of any kind. DeepEngineerHub shall not be held liable for any data loss, formatting inconsistencies, or indirect damages resulting from tool usage.

3. Open Source & Third-Party Software

Certain utilities utilize open-source client libraries (such as jsPDF, Mermaid.js, Pyodide) licensed under MIT, Apache, or BSD open licenses. All intellectual property remains with their respective copyright holders.