Streamlit app for retrieval-augmented generation (RAG) with multi-database routing, OCR ingestion, and a resilient web fallback.
- Vector store: Qdrant (3 logical DBs: products, support, finance)
- Embeddings/LLM: Gemini (Google Generative AI) with sentence-transformers fallback for embeddings
- Chat model: gemini-2.5-flash (temperature=0)
- Embeddings model: gemini-embedding-001
- Routing: Vector-first + LLM fallback routing
- Retrieval: MMR retrievers, adaptive enrichment for list-style queries
- OCR: PyMuPDF rendering + Tesseract/EasyOCR (optional OpenCV preprocessing)
- Web fallback: Direct ddgs (DuckDuckGo) search + concise LLM summarization with sources (no agent)
- Multi-database routing with calibrated thresholds and margin gating
- Dimension-aware Qdrant collections; auto-suffixed when embedding dimension changes
- PDF ingestion with rich metadata (file_name, pdf_title, page_header), plus synthetic FILE_METADATA chunks
- Optional OCR for scanned PDFs; auto-detect Tesseract/EasyOCR; optional OpenCV preproc
- Robust RAG prompts that enumerate all relevant items with short descriptions; adaptive re-ask when needed
- Cross-database aggregation before web fallback
- Web fallback without agents: direct search + LLM summarization (adds Sources)
- Clean separation:
app.py(UI) vsrag_core.py(logic)
- Python 3.10+
- Qdrant (Cloud URL + API key or local instance)
- Optional: Google API key for Gemini LLM and embeddings (if missing, embeddings fall back to sentence-transformers and LLM features are disabled)
- Without a Google API key, the app still routes and retrieves but returns top context snippets instead of generated answers.
python -m venv venv
./venv/Scripts/Activate.ps1
pip install -r requirements.txtIf you use OCR with PyMuPDF/EasyOCR, the first run may download models.
streamlit run app.pyOpen the local URL Streamlit prints.
- Qdrant URL, API Key
- Google API Key (Gemini) — enables LLM and Gemini embeddings
- Web fallback toggle (uses ddgs for web search)
- OCR toggle and OpenCV preprocessing toggle
Routing notes:
- Vector routing prints per-database scores in the UI to aid debugging (only when a question is asked).
Notes:
- Environment variables are optional (you can paste keys into the sidebar). For deployment, prefer env vars.
- Do not commit secrets. A
.gitignoreis included to protect common secret files.
- Choose a database tab (Products / Support / Finance).
- Upload PDFs (multiple allowed).
- Click Ingest. The app:
- Extracts text and metadata per page
- Optionally runs OCR (PyMuPDF render → Tesseract or EasyOCR)
- Adds synthetic FILE_METADATA chunks to help title/name questions
- Splits into chunks and stores in the chosen Qdrant collection
- Vector-first routing across collections (normalized scores; avg of top-3; margin gating)
- If unclear, LLM routing (products/support/finance/none)
- If no high-confidence target, cross-database retrieval and answer
- If still no relevant local docs, web fallback (ddgs) with LLM summarization and sources
Behavior details:
- If LLM is disabled, the app shows top context snippets instead of a generated answer.
- Web fallback includes the Sources list inside the answer text (the separate Sources panel is used only for local document chunks).
List-style queries (e.g., “projects”, “skills”) get broader retrieval and an adaptive enrichment pass if the first answer lacks descriptions or items.
- Uses ddgs (the renamed
duckduckgo_searchpackage) for direct web search - Summarizes snippets concisely and appends up to 3 sources
- If LLM is disabled, returns structured raw results (titles/snippets/links)
Notes:
- This implementation does not use an agent; it performs a direct search and then summarizes.
- The “Sources” for web answers are rendered within the answer. The UI’s Sources list is reserved for local document chunks.
Tip: To switch providers (SerpAPI, Tavily, Bing, Google PSE), add a simple search_web() adapter and swap it in handle_web_fallback.
- PyMuPDF renders each page to an image; we then apply:
- Tesseract (if available) or EasyOCR fallback
- Optional OpenCV denoise + adaptive thresholding
- OCR is attempted only if a page has very little extractable text
Windows tips:
- Tesseract OCR is optional; if not installed, the app will try EasyOCR automatically. Installing Tesseract can improve OCR quality/performance.
- A secondary fallback (
pdf2image) may require Poppler on some systems, but PyMuPDF is used first and typically suffices on Windows.
Set these for non-interactive deployments:
- GOOGLE_API_KEY =
- QDRANT_URL =
- QDRANT_API_KEY =
You can also supply them via the Streamlit sidebar locally.
- ddgs rename warning: This project uses the renamed
ddgspackage. If you see a warning aboutduckduckgo_search, update deps withpip install -r requirements.txt. - LLM disabled: Without
GOOGLE_API_KEY, you’ll still get embeddings via sentence-transformers, but answers will be raw context snippets. - Qdrant dim mismatch: The app auto-creates dimension-suffixed collections to avoid errors like “expected dim: 384, got 768”.
- DeprecationWarning on shutdown (swigvarlink): Suppressed in
app.py; it’s harmless. - Web fallback doesn’t show links in the Sources panel: This is expected—the web “Sources” are included in the answer text itself.
- Tesseract not found: The app falls back to EasyOCR. To use Tesseract, install it system-wide and ensure it’s on PATH; otherwise no action is needed.
app.py # Streamlit UI and orchestration
rag_core.py # Core: models, ingestion, routing, retrieval, web fallback
requirements.txt
README.md
