Skip to content

encryptedtouhid/FinLens

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FinLens - AI Expense Intelligence Platform

AI-powered expense categorization and anomaly detection platform built with FastAPI, Next.js 14, and GPT-4o-mini.

Features

  • AI Transaction Categorization: Automatic categorization using GPT-4o-mini with confidence scores
  • Anomaly Detection: Statistical + AI-powered detection of unusual spending patterns
  • Plaid Integration: Connect bank accounts for automatic transaction syncing
  • Idempotent APIs: Safe batch ingestion with deduplication
  • Real-time Processing: Celery-based async task queue for categorization and anomaly detection

Tech Stack

Component Technology
Frontend Next.js 14 (App Router), TypeScript, Tailwind CSS, React Query
Backend FastAPI, Python 3.11+, SQLAlchemy 2.0
Database PostgreSQL 15
Cache/Queue Redis, Celery
AI GPT-4o-mini via LiteLLM
Banking Plaid API
Observability OpenTelemetry, Prometheus, Structlog

Quick Start

Prerequisites

  • Docker & Docker Compose
  • OpenAI API key
  • Plaid sandbox credentials (optional, for bank integration)

Setup

  1. Clone and configure

    cd finlens
    cp .env.example .env
    # Edit .env with your API keys
  2. Start services

    docker-compose up -d
  3. Run migrations and seed data

    docker-compose exec backend alembic upgrade head
    docker-compose exec celery-worker python -c "from app.workers.tasks import seed_default_categories; seed_default_categories.delay()"
  4. Access the app

API Overview

Transactions

# Batch ingest transactions (idempotent)
curl -X POST http://localhost:8000/api/v1/transactions/batch \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: $(uuidgen)" \
  -d '{
    "transactions": [
      {"amount": 42.50, "description": "UBER EATS", "date": "2026-01-20"}
    ]
  }'

# List transactions with pagination
curl "http://localhost:8000/api/v1/transactions?page=1&per_page=20"

# Filter by anomaly status
curl "http://localhost:8000/api/v1/transactions?is_anomaly=true"

Anomalies

# List unreviewed anomalies
curl "http://localhost:8000/api/v1/anomalies?is_reviewed=false"

# Review an anomaly
curl -X POST http://localhost:8000/api/v1/anomalies/{id}/review \
  -H "Content-Type: application/json" \
  -d '{"is_false_positive": false, "note": "Confirmed suspicious"}'

Categories

# Get categories with stats
curl http://localhost:8000/api/v1/categories/stats

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Next.js 14 Frontend                       β”‚
β”‚          (Dashboard, Transactions, Anomalies)                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚ REST API
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    FastAPI Backend                           β”‚
β”‚     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚
β”‚     β”‚ Transactionsβ”‚  β”‚  Anomalies  β”‚  β”‚    Plaid    β”‚       β”‚
β”‚     β”‚     API     β”‚  β”‚     API     β”‚  β”‚     API     β”‚       β”‚
β”‚     β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜       β”‚
β”‚            β”‚                β”‚                β”‚               β”‚
β”‚     β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”       β”‚
β”‚     β”‚              Service Layer                     β”‚       β”‚
β”‚     β”‚  Categorizer β”‚ AnomalyDetector β”‚ Idempotency  β”‚       β”‚
β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β–Ό                    β–Ό                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  PostgreSQL β”‚    β”‚    Redis    β”‚      β”‚   Celery        β”‚
β”‚  (data)     β”‚    β”‚ (cache/     β”‚      β”‚   Workers       β”‚
β”‚             β”‚    β”‚  dedup)     β”‚      β”‚ (async tasks)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                 β”‚
                                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                                        β”‚   GPT-4o-mini   β”‚
                                        β”‚  (via LiteLLM)  β”‚
                                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Engineering Patterns

Idempotency

Transactions use SHA-256 hash of (account_id, amount, date, description) for deduplication:

  • Redis stores hashes with 24h TTL for fast lookup
  • Database has unique constraint on tx_hash
  • API accepts X-Idempotency-Key header for request-level idempotency

Backpressure

  • Celery workers with rate_limit: "50/m" for LLM calls
  • Redis-based distributed locks prevent concurrent processing
  • Queue depth monitoring via Prometheus metrics

Anomaly Detection

Weighted scoring (0-1 scale):

score = 0.4 * amount_z_score + 0.35 * merchant_novelty + 0.25 * time_pattern

Threshold: 0.6 triggers anomaly flag + LLM explanation

Development

Run Tests

docker-compose exec backend pytest -v

Run Linting

docker-compose exec backend ruff check app/
docker-compose exec frontend npm run lint

View Celery Tasks

docker-compose exec celery-worker celery -A app.workers.celery_app inspect active

Cost Estimates

Component Usage Cost/Month
GPT-4o-mini 10k transactions @ ~150 tokens ~$1.50
Plaid Sandbox Unlimited $0
Self-hosted Docker $0

License

MIT

About

AI-powered expense intelligence platform that automatically categorizes bank transactions.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors