Finsults (Finance + Insults): Project Story

Bank statements, but Gen-Z-ified. We transform chaotic transactions into clear charts and concise one-liners, so students can finally see where the money actually goes.

💡 Inspiration

We kept seeing the same pattern on campus: students swipe, tap, and DoorDash their way through the month, then open their bank app and get… a wall of transactions. No narrative. No guidance. No vibes. We wanted something that feels fun, speaks in a Gen Z tone, and still delivers real insight, not just graphs and guilt.

That’s how Finsults was born: finance + insults. Get roasted. Get better.

🧪 What We Built (at a glance)

  • PDF → Insights: Upload bank statements; we parse PDFs, extract transactions, and auto-categorize.
  • Visualized Dashboard: Recharts-powered bar/pie/area charts, time filters, and translucent purple tooltips with white text.
  • AI Roasts: Google Gemini API turns spending patterns into punchy, actionable one-liners.

- Privacy-first: PDFs aren’t stored; we keep only anonymized transaction rows.

🏗️ How We Built It

Stack

  • Frontend: Next.js (App Router), TypeScript, Tailwind, shadcn/ui, Recharts.
  • Backend: Flask + SQLite (local persistence)
  • PDF & LLM: PyMuPDF for text extraction; Google Gemini API for structured JSON; deterministic parsing guardrails.

PDF → JSON Pipeline

  1. Extract text with PyMuPDF.
  2. Prompt LLM with a strict schema (one or many statements), requesting clean JSON only.
  3. Parse safely: strip ```json fences, validate schema, and surface clear errors on failure.

Categorization

  • Canonical categories (Food & Dining, Subscriptions, Housing & Utilities, etc.) + synonym map (e.g., “DoorDash”, “groceries”, “Uber”) → deterministic labeling.
  • Edge cases go to Other. Money-in vs money-out is explicit.

Analytics & Charts

  • Filters: Last 30d, 3m, 6m, 1y (buttons wired to memoized slices).
  • Distribution & totals: percent-of-spend, largest merchants, and recent activity.

AI Roasts (Gen-Z-ified)

  • Prompts include top categories, % of spend, largest merchant, and severity.
  • Output bundles: line, alt_lines, action_hint, severity.
  • Example trigger: Food & Dining ≥ 40% → “Bestie, meet a grocery list.”

Privacy & Security

  • PDFs are not persisted; parsed rows only.
  • No client-side secrets; environment-scoped keys.
  • Clear UX copy: we don’t store PDFs, ever.

📚 What We Learned

  • Prompt design > model size for structured extraction; strict schema wins.
  • Defensive parsing prevents most LLM hiccups.
  • Micro-UX matters: gradients, tooltip contrast, and copy tone make data feel usable.
  • Batching LLM calls cuts cost/latency when done with careful input labeling.

🧱 Challenges We Faced

  • LLM JSON drift (extra commentary) → fenced JSON + schema validation.
  • Inconsistent PDFs (scans/encodings) → text cleanup and merchant heuristics.
  • Date ambiguity → normalize to ISO consistently.
  • SQLite vs Postgres quirks → standardized on SQLite placeholders and a thin DB helper.
  • Performance on long statements → batch inserts and single-call multi-file processing.

🏁 Results We’re Proud Of

  • Upload → charts + roasts in seconds.
  • Clear money-in vs money-out and top-category roast that actually nudges behavior.
  • A fun, non-shamey tone that users want to open again tomorrow.

🚀 What’s Next

  • Month-over-month comparisons and trend arrows.
  • Smart goals per category with progress tracking.
  • Anomaly flags for unusual spend.
  • Local encryption for the SQLite file.
  • TTS roasts + anonymous leaderboards (opt-in only).

Built With

Share this project:

Updates