Reading PDFs that contain figures takes more than standard text splitting. This project handles text and image extraction, uses vision models to summarize pictures, stores everything locally in ChromaDB, and cleans up questions upfront so vector searches actually pull the right pages without altering the user's original query intent during final response generation.
Multimodal PDF Processing (app.py)
PyMuPDF.qwen/qwen3.8-27b) to generate a detailed summary/description of what it contains.Persistent Vector Store & Chunking (vectordb.py)
sentence-transformers/all-MiniLM-L6-v2 for local embedding generation.Chroma with local persistence (./chroma_db) and deterministic MD5-based chunk IDs for idempotent upserts.Two-Stage Conversational Processing & Query Rewriting
graph TD %% Row 1: Ingestion & Summarization subgraph Row1 [" "] direction LR A["PDF Files<br/>in data/"] -->|"PyMuPDF<br/>Text Extract"| B["Text Pages"] A -->|"PyMuPDF<br/>Image Extract"| C["Raw Images"] C -->|"Filter < 150px<br/>& Base64"| D["Vision Model<br/>(Qwen 3.8 27B)"] D -->|"Generate<br/>Summaries"| E["Image<br/>Descriptions"] B --> F["Combined<br/>Documents"] E --> F end %% Row 2: Vector Store Indexing subgraph Row2 [" "] direction LR G["Document<br/>Chunks"] -->|"HuggingFace<br/>Embeddings"| H["Vector<br/>Embeddings"] H -->|"Upsert MD5 IDs"| I[("ChromaDB<br/>Vector Store")] end %% Link Row 1 to Row 2 F -->|"Recursive Splitter"| G %% Remove subgraph borders for a clean look style Row1 fill:none,stroke:none; style Row2 fill:none,stroke:none;
0.3.x)pymupdf)sentence-transformers/all-MiniLM-L6-v2)The behavior of the RAG system is fully modular and controlled via two YAML files in the config/ directory:
config.yaml: Manages global retrieval and conversational window parameters.
n_results: Maximum number of document chunks to retrieve per search.n_threshold: Distance score threshold for vector matching (filters out irrelevant hits).max_recent_messages: Sliding window size for retaining active chat history before triggering the background summarization chain.prompt_config.yaml: Houses the structured prompt settings for both the Query Rewriter and the final RAG Generator chain.
role, explicit instruction, output_constraints, style_or_tone, and goal.build_prompt function to dynamically construct system instructions without hard-coding them into Python scripts.While the multimodal pipeline significantly improves document intelligence over text-only RAG systems, it currently has the following constraints:
page.get_images()). Consequently, standalone vector graphics, native charts, and vector-drawn diagrams are not extracted.Create a virtual environment:
python -m venv .venv source .venv/bin/activate
Install dependencies:
pip install -r requirements.txt
Configure Environment:
Copy the example environment file to create your .env configuration:
cp .env.example .env
To process embedded images found in PDF files, ensure you specify a vision-capable model (like qwen/qwen3.8-27b) inside .env:
# Groq API Configuration (alternative to OpenAI) GROQ_API_KEY=your_groq_api_key_here VISION_MODEL=qwen/qwen3.8-27b GROQ_MODEL=openai/gpt-oss-20b # Embedding Configuration # Optional: HuggingFace model for embeddings (default: sentence-transformers/all-MiniLM-L6-v2) EMBEDDING_MODEL= # Vector Database Configuration # Optional: ChromaDB collection name CHROMA_COLLECTION_NAME= # Hugging Face token HF_TOKEN=your_hf_token_here
Prepare Data: The project includes a sample PDF in the data/ directory covering the basics of dogs and cats. You can use this default file or place any additional PDF documents you want to analyze directly inside the data/ folder.
Start the Assistant:
python app.py
Note: On startup, the system will automatically parse all PDFs located in the data/ folder, extract text and images, embed them, and ingest them into the local ChromaDB database. Since we use the 'upsert' method when adding documents to the vector store, running the script again will update existing pages and add any new ones.
Interact: Once ingestion is complete, type your questions into the terminal prompt to query your documents. Type quit to exit.
By combining targeted vector search via a rewritten query with the preservation of the user's original query in the final prompt, this setup ensures high retrieval accuracy and maintains the exact intent of the initial user interaction.