samikshabatra18/legal-document-analyzer
Legal Document Intelligence Platform
An end-to-end Retrieval-Augmented Generation (RAG) system for legal contract analysis. Upload a contract (NDA, lease, vendor agreement) and ask questions, extract clauses, surface commercial risks, and compare terms across documents — every answer grounded in page/section citations from the source PDF.
Features
- Grounded Q&A with citations — answers cite
(Page X, Section Y)for every claim and refuse when the answer isn't in the document (hallucination control). - Hybrid retrieval + reranking — semantic (vector) + BM25 keyword search, refined by a cross-encoder so exact references ("Section 5") and conceptual queries both work.
- Clause extraction — auto-tags every chunk into a clause taxonomy (Termination, Liability, Payment, Renewal, …) in one batched LLM call.
- Risk detection — flags commercially risky clauses (unlimited liability, one-sided termination, silent auto-renewal) with severity ratings, from a config-file rubric.
- Multi-document comparison — diffs key terms across contracts in a cited table.
- Evaluation harness — labeled eval set + precision@k / citation-accuracy scoring to catch regressions.
Retrieval quality (eval set, 24 items)
python -m evaluation.run_eval (retrieval metrics are local — no LLM/API cost).
Architecture
PDF upload
→ parse (pdfplumber, pypdf fallback) + clean headers/footers
→ page-aware, section-tagged chunking
→ embed (sentence-transformers BGE-small) → FAISS index
→ hybrid retrieve (vector + BM25) → cross-encoder rerank
→ grounded prompt → LLM → answer + page/section citationsClause extraction, the risk engine, and multi-document comparison run on the same ingested/indexed corpus.
Tech stack
Project structure
backend/
app.py # FastAPI entrypoint
config.py # settings loaded from .env
loaders/pdf_loader.py # PDF -> clean page text
chunking/chunker.py # page text -> section-tagged chunks
embeddings/embedding_model.py # text -> vectors
vector_db/faiss_manager.py # FAISS index + metadata
retrieval/retriever.py # vector + BM25 hybrid search
reranker/cross_encoder.py # cross-encoder rerank
qa/ # LLM interface, prompt, RAG pipeline
clause_extraction/extractor.py # clause classification
risk_analysis/ # risk rubric (json) + analyzer
comparison/comparator.py # multi-document comparison
routes/ # FastAPI routers
frontend/app.py # Streamlit UI
evaluation/ # eval set + scoring script
data/ # sample contracts
tests/ # pytest (39 tests)API
Setup
python -m venv venv
venv\Scripts\activate # Windows (use: source venv/bin/activate on macOS/Linux)
pip install -r requirements.txt
cp .env.example .env # then add your GEMINI_API_KEYGet a free Gemini key at <https://aistudio.google.com/apikey>. The key is read from .env locally (gitignored) or from the environment in deployment — never committed.
Run
# Backend (terminal 1)
uvicorn backend.app:app --reload --port 8020
# Frontend (terminal 2)
streamlit run frontend/app.pyOpen <http://localhost:8501> and upload a contract. (The backend runs on 8020 here to avoid a port conflict; set API_BASE if you use a different port.)
Tests & evaluation
pytest -q # 39 tests (LLM-dependent paths mocked)
python -m evaluation.run_eval # retrieval metrics (no API cost)
python -m evaluation.run_eval --with-answers # + citation accuracy (uses the LLM)Deployment
Ships as a single container (see Dockerfile): FastAPI internally on :8000, Streamlit publicly on :7860. On Hugging Face Spaces (Docker SDK), set GEMINI_API_KEY as a Space secret — it is never stored in the repo.
Notes
- The LLM sits behind a single
call_llm()interface, so Gemini can be swapped for OpenAI or a local Ollama model without touching the pipeline. - Clause extraction and risk detection fall back to keyword heuristics if no LLM key is configured, so the app still runs (Q&A requires the LLM).
data/sample_vendor_agreement.pdfand..._b.pdfare synthetic contracts for testing/demo (regenerate with the scripts indata/).
