Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FinePrint* AI — read before you sign

*the part they hope you don't read

Final Year Project · FastAPI + LangGraph + Groq (Llama 3.3 70B) + FAISS + PyMuPDF

The problem

Students and first-jobbers in India sign rent agreements, education-loan papers, job offers, and app T&Cs without reading them — the language is hostile by design. The traps are always the same: deposit forfeiture, one-sided notice periods, unlimited penalties, "as decided by the lender" charges. FinePrint AI reads the document for you, marks every trap, tells you exactly what to negotiate — in plain English, Hindi and Tamil — and then answers your follow-up questions in a conversation that remembers the document, grounded in the actual law of Tamil Nadu, Madhya Pradesh, and central India.

What it does

Pick your state, upload a PDF, TXT, or photo of a document. In under 90 seconds you get:

  • A verdict stamp — LOOKS FAIR / NEGOTIATE FIRST / DO NOT SIGN YET — with a 0–100 safety score
  • Clause review — every risky clause quoted, highlighted 🔴 trap / 🟡 caution / 🟢 good, explained in 2 plain sentences (EN + हिन्दी + தமிழ்), with a concrete "what to do" negotiation tip
  • Missing-protection audit — the clauses a fair document of this type SHOULD contain but doesn't, checked against a per-document-type checklist
  • Legal grounding — findings are grounded in a curated FAISS knowledge base of Indian law (TN Rent Act 2017, MP Accommodation Control Act 1961, Shops & Establishments Acts, RBI lending rules, Contract Act, Consumer Protection Act 2019, DPDP Act 2023…), filtered to your state
  • Ask FinePrint — a function-calling agent you can interrogate afterwards ("Is clause 7 risky?", "என் டெபாசிட் பணம் பாதுகாப்பானதா?") that searches the legal KB, cites acts and sections, and remembers the conversation per document
  • Printable report to take to the landlord/HR/bank

Supported document types: rent agreements, loan agreements, job offers, terms & conditions, and general contracts.

Setup (5 minutes)

cd fineprint
pip install -r requirements.txt
cp .env.example .env        # paste your Groq API key inside
python -m app.kb --rebuild  # build the FAISS legal index (downloads the embedding model once)
uvicorn app.main:app --reload

Open http://localhost:8000 and drop in sample_docs/sample_rent_agreement.txt — a realistic rental agreement seeded with 6+ classic traps, perfect for demos.

Optional (scanned PDFs / photos): install Tesseract OCR, then pip install pytesseract pillow.

Get a free Groq key: console.groq.com → API Keys. The free tier is enough; the app paces its calls to respect rate limits.

How it works (architecture)

Orchestration is a LangGraph state machine (app/graph.py) with two lanes sharing one state and one SQLite-checkpointed memory:

graph TD;
    __start__([START]):::first
    classify(classify)
    retrieve(retrieve)
    reformulate_query(reformulate_query)
    analyze(analyze)
    audit(audit)
    score(score)
    agent(agent)
    tools(tools)
    reformulate(reformulate)
    __end__([END]):::last
    __start__ -. report .-> classify;
    __start__ -. chat .-> agent;
    classify --> retrieve;
    retrieve -. "confidence ≥ 0.30" .-> analyze;
    retrieve -. "low confidence" .-> reformulate_query;
    reformulate_query --> retrieve;
    analyze --> audit;
    audit --> score;
    score --> __end__;
    agent -. "tool_calls" .-> tools;
    agent -. "answer" .-> __end__;
    tools -. "ok" .-> agent;
    tools -. "weak KB hits" .-> reformulate;
    reformulate --> agent;
    classDef first fill-opacity:0
    classDef last fill:#bfb6fc
Loading
  • Report lane (POST /api/analyze) — deterministic pipeline: classify → retrieve → analyze → audit → score. Retrieval pulls the 6 most relevant legal rules from the FAISS KB (jurisdiction-filtered to the user's state) and injects them into the clause-analysis and audit prompts, so risk calls cite actual statutes.
  • Chat lane (POST /api/chat) — a function-calling agent (bind_tools) dispatching across 5 tools: search_legal_kb, analyze_clause_risk, audit_missing_protections, summarize_document, extract_document_text. A custom tool node injects graph state (the loaded document, the jurisdiction) into tool runs.
  • Self-correction loop — every KB search carries a confidence score (mean top-3 cosine similarity). Below 0.30, a reformulate node rewrites the query with different legal terminology and retries — bounded at 2 retries by a retry_count in state, so it can never loop forever.
  • Conversation memory — a SqliteSaver checkpointer persists the full graph state per thread_id at every super-step. /api/analyze returns the thread_id; follow-up /api/chat calls on it remember the document, the report, and the dialogue.

Components

  • app/graph.py — the state machine above: ContractState (TypedDict with add_messages), nodes, conditional edges, checkpointer.
  • app/kb.py + app/legal_kb/rules.json — the legal KB: 42 curated plain-language rules (each with act, section, English text + Tamil/Hindi translations, doc-type tags, jurisdiction TN/MP/IN), embedded with paraphrase-multilingual-MiniLM-L12-v2 — one vector space for English, Tamil, and Hindi, so «வேலை நீக்கம் நோட்டீஸ் இல்லாமல்» retrieves the English-indexed termination rule — searched via FAISS inner product over normalized vectors (= cosine, giving the 0–1 confidence signal).
  • app/tools.py — the agent's tools with API-doc docstrings (what the LLM reads to choose a tool). analyze_clause_risk uses with_structured_output on a Pydantic schema.
  • app/schemas.py — Pydantic contracts: every report is validated through RiskReport before leaving the API.
  • app/analyzer.py — the LLM steps (classify / clause findings / checklist audit) with strict-JSON prompts and defensive parsing that can even salvage complete findings from a token-truncated reply. Scoring stays deterministic Python, not LLM: 100 − 14/red − 6/yellow − 8/missing − 4/vague, +2 per good clause, clamped 3–100.
  • app/checklists.py — per-document-type fairness checklists, encoded outside the model.
  • app/extractor.py — PyMuPDF text extraction with OCR fallback for scans/photos.
  • app/static/index.html — zero-framework frontend: state selector, drag-drop upload, verdict stamp, clause cards, English/हिन्दी/தமிழ் toggle, chat panel with cited acts, print stylesheet.

Demo script (for review/viva)

  1. Pick Tamil Nadu, upload the sample rent agreement → DO NOT SIGN YET stamp.
  2. Point at the red flag: "entire security deposit shall stand forfeited" — and note the explanation now cites the TN Rent Act 2017 cap of two months' deposit.
  3. Toggle to தமிழ் — same analysis, mother tongue. Toggle हिन्दी — same again.
  4. Show the missing-protection audit: no deposit-refund timeline — a trap by omission.
  5. Ask FinePrint: "Can the landlord evict me without notice?" — watch it call search_legal_kb, answer with the act and section cited under the bubble, then ask a follow-up ("and what about the deposit?") to show thread memory.
  6. Show python -m app.graph printing the state machine, and this README's diagram.

Viva talking points

  • Why a graph over a chain? The pipeline has cycles (the low-confidence → reformulate → retrieve loop) and conditional routing (report vs chat lane, tools vs answer) — a DAG/chain can't express either.
  • How does bind_tools work? Tool schemas (from the docstrings + signatures) are injected into the request; the model emits structured tool_calls; the tool node executes them and returns ToolMessages; the loop continues until the model answers without tool calls.
  • How do you prevent infinite loops? retry_count lives in graph state; the conditional edge checks it against a bound (2) before routing to reformulate. Plus a recursion limit on invoke.
  • What does the checkpointer persist? The full ContractState per thread_id at each super-step — messages, document text, doc metadata, retrieved rules — in SQLite (fineprint_memory.db).
  • Retrieval confidence = mean top-3 cosine similarity (threshold 0.30, calibrated against junk vs relevant queries). Self-correction measurably works: "प्रीपेमेंट पेनल्टी" scores 0.26 raw, 0.56 after terminology reformulation.
  • Trust boundary: the LLM explains; the score is deterministic Python; the law comes from a reviewable JSON corpus, not model memory. Citations let the user verify.
  • Honest limitations: not legal advice (disclaimer in UI); the KB is a curated student corpus, not a complete statute database; LLM Tamil/Hindi phrasing can be imperfect (KB rule translations are human-written, model explanations are generated); OCR quality bounds photo uploads; analysis caps at ~15 pages.

Extension ideas (roadmap slide)

  • More states: the KB is a JSON file — add Karnataka/Maharashtra rules and a dropdown entry each
  • Compare two versions of an agreement ("what changed after negotiation?")
  • WhatsApp bot front-end (photo in → report out)
  • Streaming chat responses (LangGraph astream) and a visible "agent is searching the KB…" trace in the UI

Project structure

fineprint/
├── app/
│   ├── main.py            # FastAPI: /api/analyze + /api/chat -> graph
│   ├── graph.py           # LangGraph state machine (2 lanes, retry loops, checkpointer)
│   ├── tools.py           # 5 function-calling tools + Groq LLM factory
│   ├── kb.py              # FAISS legal KB: build / search / confidence
│   ├── legal_kb/rules.json# 42 curated rules: TN + MP + central law (EN/TA/HI)
│   ├── schemas.py         # Pydantic RiskReport & structured-output models
│   ├── analyzer.py        # LLM steps + defensive JSON parsing + deterministic score
│   ├── checklists.py      # fairness checklists per document type
│   ├── extractor.py       # PDF/image/txt -> text (OCR fallback)
│   └── static/index.html  # frontend (no framework): report + trilingual toggle + chat
├── sample_docs/sample_rent_agreement.txt   # demo doc with seeded traps
├── smoke_test.py          # offline tests: both lanes, retry loop, memory (mocked LLM+KB)
├── requirements.txt
└── .env.example

Run the tests any time with python smoke_test.py — they mock the LLM and the KB, so they're free and offline.

About

Agentic contract risk analyzer: LangGraph state machine grounded in 42 Indian statutes via FAISS

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages