Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“š DocuMind β€” A Local RAG-Powered Document Q&A Assistant

A completely offline, private AI assistant that answers questions using the actual text of your own PDF documents β€” built from scratch using Python, without relying on any paid API (no OpenAI, no internet needed after setup).


πŸ€” What does this project actually do?

Imagine you have a friend who has read every document you give them cover to cover, and whenever you ask a question, they:

  1. Flip to the exact page that talks about your topic
  2. Read it
  3. Explain it back to you in their own words

That's exactly what this project does β€” except the "friend" is a small AI model running on my own laptop, and the "flipping to the right page" happens automatically in milliseconds.

This is called RAG β€” Retrieval-Augmented Generation. Instead of an AI just guessing answers from what it vaguely remembers (which can be wrong), it first looks up the real content, then answers based on what it found.

You can point this at any set of PDFs β€” textbooks, research papers, manuals, notes, reports β€” and it turns them into a searchable, question-answerable knowledge base.


❓ Why not just use ChatGPT?

Great question. Here's the difference:

ChatGPT / Cloud AI This Project
Needs internet Yes Only during setup
Costs money Sometimes (API/subscription) 100% free
Your data Sent to a company's server Stays on your laptop
Knows your exact documents No β€” answers from general training, can be wrong or make things up Yes β€” reads and quotes your actual uploaded PDFs
Can it lie confidently? Yes (this is called "hallucination") Much less β€” if it can't find the answer in your documents, it says "I don't know" instead of guessing

I actually ran into this problem while building this β€” I asked a plain (non-RAG) local AI model about a specific document's content, and it completely made up a fake answer that didn't exist in the real source. That's exactly the problem RAG solves.


🧠 How it works (the simple version)

Think of the whole system as a 4-step assembly line:

Your PDF documents
      ↓
[1] CHOP into small text pieces (chunks)
      ↓
[2] CONVERT each piece into a list of numbers (embeddings)
      ↓
[3] STORE those numbers in a searchable database (FAISS)
      ↓
When you ask a question:
   β†’ your question also becomes numbers
   β†’ the database finds the 3 most similar chunks
   β†’ those chunks + your question are sent to the AI model
   β†’ the AI reads them and writes you a real answer

Why numbers (embeddings)?

Computers can't "understand" meaning the way we do, but they're great at math. An embedding model converts text into a list of numbers (a vector) that represents its meaning. Sentences with similar meaning end up with similar numbers β€” even if they use totally different words. This is how the system finds relevant content even if you phrase your question completely differently from the source text.


πŸ› οΈ The Tools Used (and what each one is for)

Tool Role Analogy
Ollama Runs the AI language model on my laptop The "brain" that reads and writes answers
Llama 3.2 The actual AI model (open-source, made by Meta) The specific person doing the thinking
LangChain Python framework that connects all the pieces together The wiring/glue between all the parts
PyMuPDF Extracts raw text out of PDF files The person reading each document page by page
sentence-transformers (all-MiniLM-L6-v2) Converts text into embeddings (numbers) Translator that turns sentences into "meaning-fingerprints"
FAISS (by Meta) Stores embeddings and searches them super fast The librarian who instantly finds the right page
Python The programming language tying it all together β€”

Everything here is free and open-source. No API keys, no subscriptions, no credit card.


πŸ“ Project Structure

DocuMind/
β”œβ”€β”€ data/
β”‚   β”œβ”€β”€ folder1/               ← put related PDFs here
β”‚   └── folder2/                ← put another category of PDFs here
β”œβ”€β”€ faiss_index/                 ← auto-generated searchable database (created by ingest.py)
β”œβ”€β”€ rag_env/                     ← Python virtual environment (keeps dependencies isolated)
β”œβ”€β”€ ingest.py                    ← Step 1 script: reads PDFs, builds the database
β”œβ”€β”€ query.py                     ← Step 2 script: lets you ask questions
└── README.md                    ← this file

The data/ folder can be organized however makes sense for your use case β€” by subject, by project, by year, etc. The script reads every PDF inside it, including subfolders.


βš™οΈ How to Run It Yourself

Prerequisites

  • Python installed
  • Ollama installed, with a model pulled:
    ollama pull llama3.2
image

Step 1 β€” Set up the environment

python -m venv rag_env
rag_env\Scripts\activate        # Windows
pip install langchain langchain-community langchain-ollama langchain-huggingface langchain-text-splitters langchain-classic faiss-cpu sentence-transformers pymupdf

Step 2 β€” Add your documents

Drop your PDF files into folders inside data/.

Step 3 β€” Build the searchable database (run once)

python ingest.py

This reads every PDF, breaks it into chunks, converts them to embeddings, and saves a faiss_index/ folder. You only need to re-run this if you add new PDFs.

Step 4 β€” Ask questions!

python query.py

Type any question about your documents and get an answer grounded in the actual content. Type quit to exit.


πŸ’¬ Example Interaction

Ask a question (or 'quit'): what is bowman's capsule

Answer: According to the source text, Bowman's capsule is a cup-shaped 
end of a coiled tube that collects the filtrate from the cluster of 
very thin-walled blood capillaries, also known as nephrons, in the kidney.
Ask a question (or 'quit'): what is abscisic acid

Answer: I don't know what the answer to the question "What is abscisic 
acid?" is based on the provided context. The context doesn't mention 
anything about abscisic acid.

Notice the second answer β€” it honestly says it doesn't know rather than making something up, because that topic isn't covered in the documents I loaded. This is intentional and is actually a good sign β€” it means the system is staying grounded in real source material instead of guessing.


🧩 Code Walkthrough

ingest.py β€” builds the knowledge base

# 1. Load every PDF from the data folder
documents = []
for root, dirs, files in os.walk("data"):
    for file in files:
        if file.endswith(".pdf"):
            loader = PyMuPDFLoader(os.path.join(root, file))
            documents.extend(loader.load())

# 2. Split the extracted text into small overlapping chunks
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100)
chunks = splitter.split_documents(documents)

# 3. Convert chunks into embeddings and store them in FAISS
embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
vectorstore = FAISS.from_documents(chunks, embeddings)
vectorstore.save_local("faiss_index")

Why chunk size 800 with 100 overlap? Chunks need to be small enough to be specific (so retrieval finds exactly the relevant bit), but not so small that they lose context. The overlap ensures a sentence isn't awkwardly cut in half between two chunks.

query.py β€” answers your questions

# Load the saved database
vectorstore = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})  # fetch top 3 matches

# Connect to the local AI model
llm = OllamaLLM(model="llama3.2")

# Chain retrieval + generation together
qa_chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)

# Ask in a loop
while True:
    query = input("Ask a question: ")
    result = qa_chain.invoke({"query": query})
    print(result["result"])

k=3 means: for every question, grab the 3 most relevant chunks from the documents and hand them to the AI as reference material before it answers.


πŸ› Problems I Ran Into (and Fixed)

Building this wasn't just copy-pasting code β€” here's what actually broke and how I debugged it:

  1. ModuleNotFoundError: langchain.text_splitter β€” LangChain restructured its packages in newer versions; the text splitter moved to a standalone langchain_text_splitters package.
  2. pypdf.errors.LimitReachedError β€” the default PDF loader (pypdf) has a safety limit that some image-heavy PDFs (with diagrams) exceeded. Fixed by switching to PyMuPDF, a more robust PDF text extractor.
  3. RetrievalQA import errors β€” in LangChain 1.x, several chains moved into a separate langchain-classic package.

These are the kinds of real-world dependency/versioning issues you run into with any actively-developed library β€” not bugs in the core logic.


πŸš€ Possible Future Improvements

  • Show which PDF and page number each answer came from (source citation)
  • Build a simple web interface using Streamlit instead of the terminal
  • Support more file formats (Word docs, plain text, web pages)
  • Experiment with different chunk sizes to improve answer accuracy
  • Add a fallback mode that clearly labels answers as "from documents" vs "general knowledge"

πŸ“– Key Concepts Glossary (for anyone new to this)

  • LLM (Large Language Model): An AI trained on huge amounts of text that can understand and generate human-like language. Llama 3.2 is the LLM used here.
  • Embedding: A way of converting text into numbers that represent its meaning, so similar ideas end up with similar numbers.
  • Vector Database: A database built specifically to store and search embeddings quickly. FAISS is the one used here.
  • Chunking: Breaking long documents into smaller pieces so they're easier to search and fit into the AI's context.
  • Hallucination: When an AI confidently generates false information instead of admitting it doesn't know. RAG helps reduce this.
  • Retrieval: The process of searching for and pulling out the most relevant pieces of information before generating an answer.

πŸ™‹ Why I Built This

I wanted to understand how modern AI tools like ChatGPT-with-your-documents actually work under the hood, instead of just using no-code tools. Building this from raw Python taught me about embeddings, vector search, LLM orchestration, and real dependency-debugging β€” skills that a drag-and-drop tool wouldn't have taught me.

alt text

alt text

alt text

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages