Skip to content

Latest commit

 

History

60 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🇮🇳 TaxAI India

Your AI-Powered Chartered Accountant, in Code Form

Deterministic tax computation you can trust, wrapped in an AI experience people actually want to use.

FastAPI React SQLAlchemy Groq Tests Python Status

Demo Video · Quick Start · API Reference · Architecture

TaxAI India Dashboard

Why this exists

Filing taxes in India means juggling two regimes, a dozen deduction sections, AIS/26AS reconciliation, and financial documents scattered across PDFs, screenshots, and bank exports. A CA fixes all of that for a fee. TaxAI does it in software — it turns raw CSVs and photographed documents into a reconciled, regime-compared, rebate-and-cess-correct tax computation, with a conversational assistant sitting on top of the same numbers the engine computed (not a hallucinated guess).

The core design bet: the LLM never does arithmetic. Groq is used for document classification, OCR-to-CSV conversion, and natural-language answers — every rupee of tax owed is computed by deterministic Python in tax_engine.py and the FY-specific slab tables in tax_rules/. That split is what makes the numbers auditable.


✨ Feature Highlights

🧠 AI Tax Assistant Conversational Q&A grounded in the user's own computed dashboard data — refunds, deductions, GST, regime comparisons — with a hard refusal for anything non-tax
📄 Multi-Format Document Intake CSV or photographed documents (.png/.jpg/.webp/.tif/.bmp) across 9 document types — bank statements, AIS, Form 16, sales/purchase registers, capital gains statements, interest certificates, rent summaries, deduction proofs
🔎 OCR → LLM → Structured CSV Tesseract extracts raw text from images, Groq converts it into a document-type-aware CSV schema, which then flows through the same validated parser as native CSV uploads
⚖️ Old vs New Regime Engine Progressive slab computation for both regimes with FY 2024-25 rules, Section 87A rebate (₹12,500 @ ≤₹5L old / ₹25,000 @ ≤₹7L new), 4% Health & Education Cess, and automatic "pick the cheaper regime" mode
🧾 Job-Based Filing Pipeline Create a filing job → attach documents → process → review reconciliation issues → approve → export an ITR-ready PDF, with full status tracking (uploaded → parsed → normalized → reconciled → computed → needs_review → approved → exported)
💳 Transaction Intelligence Every bank/register row is parsed, merchant-normalized, Groq-categorized (with confidence scores), and persisted individually for the transactions dashboard
📊 GST & Business Bookkeeping For small-business profiles: ledger generation, P&L, balance sheet, and GST liability computation from sales/purchase registers
🔐 Hardened by Design JWT auth with mandatory expiry, startup secret validation (refuses to boot on default/weak secrets), IDOR-safe data isolation, upload size limits, and password-length DoS protection — see Security

🏗️ Architecture

flowchart LR
    subgraph Client["🖥️ Frontend — React 18 + Vite + Tailwind"]
        UI["Landing · Auth · Dashboard · Upload<br/>Tax Center · Filing · Transactions · AI Assistant"]
    end

    subgraph API["⚙️ Backend — FastAPI"]
        AUTHR["auth.py<br/>register / login / me"]
        TAXR["tax_api.py<br/>analyze · jobs · transactions · dashboard"]
        SEC["security.py<br/>JWT issue + verify"]
    end

    subgraph Services["🧠 Service Layer"]
        ING["document_ingestion.py<br/>schema validation & CSV parsing"]
        OCR["image_ocr.py<br/>Tesseract OCR"]
        AI["groq_ai.py / ai_extraction.py<br/>classification + enrichment"]
        ENGINE["tax_engine.py + tax_rules/<br/>slabs · rebate · cess"]
        JOBS["tax_jobs.py<br/>filing job orchestration"]
        BOOKS["bookkeeping.py / gst.py<br/>ledger, P&L, GST"]
    end

    subgraph Data["🗄️ Persistence"]
        DB[("PostgreSQL (prod)<br/>SQLite (tests)<br/>via SQLAlchemy")]
    end

    GROQ[["☁️ Groq Cloud API"]]

    UI -- "Bearer JWT over HTTPS" --> TAXR
    UI -- "credentials" --> AUTHR
    AUTHR --> SEC
    TAXR --> SEC
    TAXR --> ING
    TAXR --> OCR
    OCR --> AI
    ING --> AI
    AI -- HTTPS --> GROQ
    TAXR --> JOBS
    JOBS --> ENGINE
    JOBS --> BOOKS
    JOBS --> DB
    AUTHR --> DB
    TAXR --> DB
Loading

Why this split matters: the service layer has no knowledge of HTTP, and tax_engine.py has no knowledge of Groq or the database — it's pure functions over pandas.DataFrames and dicts. That's what makes 12+ tax-computation regression tests possible without spinning up a server.


🔄 Document → Tax Computation Pipeline

This is the actual data flow behind POST /api/tax-assistant/analyze and the job-based process endpoint — traced end-to-end during a full correctness audit of the repo.

flowchart TD
    A["📤 Upload document<br/>CSV or image"] --> B{File type?}
    B -- image --> C["Tesseract OCR<br/>→ Groq text-to-CSV"]
    B -- CSV --> D["Schema validation<br/>document_ingestion.py"]
    C --> D
    D --> E["Classify by document_type<br/>bank_statement · ais · form16 · sales/purchase_register<br/>interest_certificate · rent_summary · capital_gains_statement · deduction_proof"]
    E --> F["Groq enrichment (bank rows only)<br/>merchant · category · confidence"]
    F --> G["Normalize into canonical frames<br/>bank_transactions · ais_entries · form16_summaries"]
    G --> H["Merge special-document income into AIS<br/>certificates are authoritative for their income type<br/>— replaces, never adds, to prevent double-counting"]
    H --> I["build_tax_computation()<br/>tax_engine.py"]
    I --> J["Old regime slabs"]
    I --> K["New regime slabs"]
    J --> L{"regime == auto?<br/>pick lower liability"}
    K --> L
    L --> M["Apply Section 87A rebate<br/>+ 4% Health & Education Cess"]
    M --> N["Income / deduction breakdown<br/>+ regime recommendation"]
    N --> O["✅ JSON response<br/>tax_result + business_result"]
Loading

Correctness note: capital gains are surfaced under special_rate_income with an explicit compliance warning rather than silently taxed at slab rates — the engine does not (yet) apply STCG/LTCG special-rate schedules, and says so instead of guessing.


🔐 Auth & Data Isolation

sequenceDiagram
    actor U as User
    participant F as React SPA
    participant A as /api/auth
    participant S as security.py
    participant DB as Database

    U->>F: PAN + email + mobile + password
    F->>A: POST /register
    A->>A: Validate PAN/email/mobile regex, 8–128 char password
    A->>DB: INSERT user (PBKDF2-SHA256 hash)
    Note over A,DB: Duplicate email/PAN/mobile → 409, not a 500
    A->>S: create_access_token(user.id)
    S-->>A: JWT (HS256, exp: 15 min, type="access")
    A-->>F: 201 + access_token

    U->>F: GET /jobs (later, authenticated)
    F->>A: Authorization: Bearer <JWT>
    A->>S: decode_access_token()
    S->>S: verify signature · exp · type == "access"
    S-->>A: user_id
    A->>DB: SELECT ... WHERE user_id = :id
    Note over A,DB: every job/transaction/document query<br/>is scoped to the caller's user_id
    DB-->>A: caller's rows only
    A-->>F: 200
Loading

Security posture

  • No boot on weak secrets — the app refuses to start if SECRET_KEY/JWT_SECRET_KEY are missing, short, or a known placeholder (change-this-secret-key, secret, etc.)
  • JWTs always expire — token creation raises rather than issuing a non-expiring token if JWT_ACCESS_TOKEN_EXPIRES_MINUTES <= 0, and the type claim is checked on every request
  • IDOR-safe by construction — every job/transaction lookup filters by (job_id, user_id) together, never job_id alone; verified with a dedicated IDOR test suite
  • Upload limits enforced server-side — MAX_UPLOAD_BYTES (default 10 MB) is checked against the actual bytes read, not the Content-Length header
  • Password DoS guarded — passwords are capped at 128 characters before hashing (PBKDF2 cost scales with input length)
  • CORS configured correctly — allow_credentials=False paired with explicit origin allowlisting, avoiding the wildcard-origin + credentials footgun

🗄️ Data Model

erDiagram
    USERS ||--o{ TAX_FILING_JOBS : owns
    TAX_FILING_JOBS ||--o{ TAX_DOCUMENT_UPLOADS : contains
    TAX_FILING_JOBS ||--o{ TRANSACTION_RECORDS : contains
    TAX_DOCUMENT_UPLOADS ||--o{ TRANSACTION_RECORDS : "parsed into"

    USERS {
        int id PK
        string name
        string pancard_number UK
        string email UK
        string mobile_number UK
        string password_hash
    }
    TAX_FILING_JOBS {
        int id PK
        string job_id UK "UUID, public identifier"
        int user_id FK
        string profile_type "individual | small_business"
        string regime_preference "old | new | auto"
        string status "uploaded..exported"
        json processing_result
    }
    TAX_DOCUMENT_UPLOADS {
        int id PK
        int job_id FK
        string document_type
        string source_name
        text raw_content
        string parse_status
    }
    TRANSACTION_RECORDS {
        int id PK
        int job_id FK
        int document_upload_id FK
        string transaction_date
        float amount
        string txn_type "income | expense"
        string category
        float confidence
    }
Loading

Cascade deletes are wired so removing a TaxFilingJob cleans up its documents and transactions automatically — no orphaned rows.


🧩 Tech Stack

Backend

  • FastAPI (async routes, lifespan-managed startup)
  • SQLAlchemy ORM (scoped_session, PostgreSQL / SQLite)
  • PyJWT (HS256) + Werkzeug PBKDF2 password hashing
  • pandas (tax computation & ledger transforms)
  • Groq SDK (LLM classification & OCR text conversion)
  • pytesseract + Pillow (image OCR)
  • pytest (57 tests: auth, security, IDOR, tax math, uploads, Groq)

Frontend

  • React 18 + Vite 6
  • React Router 7
  • Tailwind CSS
  • Context API for auth state (AuthContext)

📁 Project Structure

TaxAI/
├── Backend/
│   ├── app.py                    # FastAPI app factory + lifespan + CORS
│   ├── auth.py                   # register / login / me
│   ├── tax_api.py                # analyze, jobs, transactions, dashboard, PDF export
│   ├── security.py               # JWT issue + verify
│   ├── config.py                 # env config + startup secret validation
│   ├── models.py                 # User, TaxFilingJob, TaxDocumentUpload, TransactionRecord
│   ├── services/
│   │   ├── tax_engine.py         # regime-agnostic slab computation
│   │   ├── tax_rules/            # FY-specific slab tables (e.g. individual_fy_2024_25.py)
│   │   ├── tax_jobs.py           # job pipeline: attach → process → approve
│   │   ├── tax_assistant.py      # one-shot /analyze pipeline + AI Q&A fallback
│   │   ├── document_ingestion.py # per-document-type schema validation
│   │   ├── document_catalog.py   # multi-document parsing orchestration
│   │   ├── image_ocr.py          # Tesseract OCR → Groq CSV conversion
│   │   ├── groq_ai.py            # Groq HTTP/SDK client + label allowlisting
│   │   ├── ai_extraction.py      # canonical tax-model extraction
│   │   ├── transactions.py       # per-row transaction sync + dashboard summaries
│   │   ├── bookkeeping.py / gst.py  # ledger, P&L, balance sheet, GST
│   │   ├── reconciliation.py     # cross-document consistency checks
│   │   ├── itr_mapper.py         # canonical model → ITR draft
│   │   └── optimization.py       # tax-saving recommendations
│   └── tests/                    # pytest suite (auth, security, IDOR, tax, uploads, groq)
└── Frontend/
    └── src/
        ├── pages/                # Landing, Auth, Dashboard, Upload, TaxCenter,
        │                         # Filing, Transactions, AIAssistant, Settings
        ├── components/           # AppLayout, ProtectedRoute
        └── context/              # AuthContext

🚀 Quick Start

Backend

cd Backend
pip install -r requirements.txt

Create Backend/.env:

SECRET_KEY=replace-with-32+-random-characters
JWT_SECRET_KEY=replace-with-a-different-32+-random-string
JWT_ACCESS_TOKEN_EXPIRES_MINUTES=15
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/taxai
GROQ_API_KEY=your-groq-key        # optional — falls back to heuristics if unset
GROQ_ENABLED=true                  # optional, default false
CORS_ALLOWED_ORIGINS=http://localhost:5173

The app will not start without a sufficiently random SECRET_KEY/JWT_SECRET_KEY — this is intentional (see Security posture).

python app.py
# → http://localhost:8000  (docs at /docs, health at /health)

Frontend

cd Frontend
npm install
npm run dev
# → http://localhost:5173

Run the test suite

cd Backend
python -m pytest tests/ -v

📡 API Reference

Auth — /api/auth
Method Path Description
POST /register Create account (name, PAN, email, mobile, password) → JWT
POST /login Login with email or PAN + password → JWT
GET /me Current user profile (requires Authorization: Bearer)
Tax Assistant — /api/tax-assistant
Method Path Description
GET /options Supported profile types, regimes, document types, provider status
POST /analyze One-shot analysis from inline CSV documents (JSON body)
POST /analyze-files One-shot analysis from uploaded files (multipart)
POST /ask Ask the AI assistant a tax question, grounded in the caller's dashboard
POST /jobs Create a filing job
GET /jobs List the caller's filing jobs
POST /jobs/{job_id}/documents Attach documents (CSV or image) to a job
POST /jobs/{job_id}/process Run the full pipeline: parse → reconcile → compute → draft ITR
GET /jobs/{job_id}/review Full processing result + reconciliation issues
POST /jobs/{job_id}/approve Approve the reviewed draft
GET /jobs/{job_id}/export/itr-pdf Export an ITR-draft PDF (job must be approved)
GET /dashboard/financial-data Latest processed job, shaped for the dashboard UI
GET /transactions Paginated transaction list (capped at 500/request), filterable by job_id

Every route above except /register, /login, and /options requires Authorization: Bearer <token> and is scoped to the authenticated user.


🧪 Testing

57 passed in ~2.6s
Suite Covers
test_auth.py Registration validation, duplicate-conflict handling, login, password bounds
test_security.py Secret validation, JWT expiry enforcement, expired-token rejection
test_idor.py Cross-user job access is blocked on review, upload, process, and list endpoints
test_tax_computation.py Rebate thresholds, regime slab math, special-document income inclusion, AIS double-counting prevention
test_uploads.py Upload size limits, valid-CSV acceptance, transaction pagination caps
test_groq_ai.py Partial-batch failure accounting, label/category allowlist coercion

🗺️ Roadmap

  • ITR e-filing portal integration
  • Live AIS / Form 26AS verification against the IT department
  • Full GST return filing support
  • Special-rate capital gains computation (STCG/LTCG schedules)
  • Investment & tax-saving recommendation engine

👨‍💻 Contributors

  • Kawaljeet Singh
  • Harsh Pachauri
  • Akshit Maheshwari
  • Divyam Gupta

📜 License

Built for educational and hackathon purposes.

About

An intelligent platform that simplifies tax planning, compliance, and financial insights for freelancers, students, creators, and small businesses.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages