Ask questions about financial PDFs and get grounded, page-cited answers — or compare two documents side by side.
🚀 Live Demo → fin-doc-intel.streamlit.app
- RAG Q&A — Ask natural-language questions across one or multiple indexed documents; every claim is traced back to a specific page
- Two-stage retrieval — Qdrant cosine search (top 15 candidates) followed by Gemini re-ranking (top 5), for precision without sacrificing recall
- Document comparison — Select any two indexed documents and get a structured, topic-by-topic analysis with separate page citations per document
- Page-level citations — Answers reference exact page numbers; source text is shown in expandable citation boxes
- Multi-document ingestion — Upload PDFs via the sidebar; chunked, embedded, and indexed in seconds
- Answer caching — Repeated questions return instantly at zero API cost (1-hour TTL)
- Graceful error handling — Rate-limit (429) and overload (503) errors shown as friendly retry messages
flowchart LR
subgraph Ingestion
A[PDF Upload] --> B[PyMuPDF Parser]
B --> C[Semantic Chunker\n512 tok · 64 overlap]
C --> D[Embedder\nall-MiniLM-L6-v2\n384-dim]
D --> E[(Qdrant Cloud)]
end
subgraph Q&A
F[User Question] --> G[Embedder]
G --> H[Vector Search\ntop 15]
E --> H
H --> I[Gemini Re-ranker\ntop 5]
I --> J[Answer Generator\nGemini 2.5 Flash]
J --> K[Answer + Citations]
end
subgraph Comparison
L[Doc A + Doc B] --> M[Dual Retriever\n8 chunks each]
E --> M
M --> N[Comparator\nGemini 2.5 Flash]
N --> O[Structured Analysis\nSource A & B citations]
end
| Layer | Technology |
|---|---|
| LLM | Google Gemini 2.5 Flash (google-genai) |
| Embeddings | sentence-transformers — all-MiniLM-L6-v2 (local, 384-dim) |
| Vector DB | Qdrant Cloud |
| PDF parsing | PyMuPDF (fitz) |
| Backend | FastAPI + Uvicorn |
| Frontend | Streamlit (deployed on Streamlit Cloud) |
| Validation | Pydantic v2 |
| Config | python-dotenv + .env |
| Upload & Index | Ask Questions | Compare Documents |
|---|---|---|
![]() |
![]() |
![]() |
Note: Drop screenshots into
docs/screenshots/to populate this table.
- Python 3.11+
- A Google AI Studio API key (with billing enabled for production use)
- A Qdrant Cloud cluster (free tier works)
git clone https://github.com/singhsudhir/fin-doc-intel.git
cd fin-doc-intel
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txtcp .env.example .envEdit .env with your credentials:
GEMINI_API_KEY=your_gemini_api_key
QDRANT_URL=https://your-cluster.qdrant.io
QDRANT_API_KEY=your_qdrant_api_keyOption A — Standalone Streamlit (no backend needed):
streamlit run streamlit_app.pyOption B — FastAPI backend + Streamlit frontend:
# Terminal 1
uvicorn src.api.main:app --reload --port 8000
# Terminal 2
streamlit run src/frontend/app.pyOpen http://localhost:8501 in your browser.
- Upload a financial PDF using the sidebar (annual reports, credit memos, etc.)
- Wait for ingestion to complete — the document appears in the Indexed Documents list
- Type a question in the Ask Questions tab and click Ask ▶
- Upload a second document and use the Compare Documents tab for side-by-side analysis
- Fork this repo and connect it to Streamlit Cloud
- Set Main file path to
streamlit_app.py - Add secrets under Settings → Secrets:
GEMINI_API_KEY = "your_key"
QDRANT_URL = "https://your-cluster.qdrant.io"
QDRANT_API_KEY = "your_key"- Deploy — no separate backend server required.
See .streamlit/secrets.toml.example for reference.
The FastAPI backend exposes the following REST API (available when running Option B):
| Method | Path | Description |
|---|---|---|
POST |
/ingest |
Upload and index a PDF file |
POST |
/query |
Ask a question, receive answer + citations |
POST |
/query/compare |
Compare two indexed documents |
GET |
/documents |
List all indexed documents |
DELETE |
/documents/{name} |
Remove a document and its vectors |
GET |
/health |
Liveness check |
fin-doc-intel/
├── streamlit_app.py # Standalone Streamlit Cloud entry point
├── src/
│ ├── api/ # FastAPI app and route handlers
│ │ └── routes/ # ingest.py, query.py, documents.py, health.py
│ ├── ingestion/ # PDF parsing and ingestion pipeline
│ ├── chunking/ # Semantic chunking (sliding window, tiktoken)
│ ├── embedding/ # Sentence-transformers wrapper + Qdrant store
│ ├── retrieval/ # Two-stage retriever (vector search + re-ranking)
│ ├── generation/ # Gemini answer generator, comparator, utils
│ ├── models/ # Pydantic schemas and response models
│ └── frontend/ # Original Streamlit app (backend-coupled)
├── tests/ # pytest test suite
├── .streamlit/
│ ├── config.toml # Theme configuration
│ └── secrets.toml.example # Secrets template
├── .env.example # Environment variable template
├── requirements.txt # Pinned dependencies
└── CLAUDE.md # Developer notes
pytest tests/ -vTests that touch Qdrant use a dedicated
test_collection prefix and require valid environment variables.
This project is licensed under the MIT License.


