PERSONAL PROJECT
Expense Analyzer
A bank statement goes in; a clear picture of where your money went comes out. The statement is read in your browser and never uploaded. No sign-up. No login.
- Type
- Personal project
- Input
- Bank statement · PDF or CSV
- Runs
- In your browser · no upload, sign-up or login
- Built with
- JavaScript · IndexedDB · WebLLM on WebGPU
What it does
You add a bank statement (a PDF or CSV file). The app sorts each payment into Spent, Income, Invested or Moved, so you can see where your money went. You can check and fix anything it gets wrong.
How it works
Your statement is read in this browser, not uploaded. No sign-up. No login.
Under the hood there is no backend at all. The app is a set of static files: plain JavaScript modules with no framework and no build step. It installs as a progressive web app and keeps working offline. Every payment goes through a layered decision engine: rules that can explain themselves come first, an optional AI model comes last, and you have the final say.
The decision engine
- Deterministic first. Each payment is checked against your own earlier choices, then your rules, then a built-in dictionary of everyday words, then words learned from your fixes. The first layer that is confident decides. A layer only answers when it is sure; otherwise the payment falls through to the next layer instead of being guessed.
- AI last, and optional. If no layer is confident, a small open model (Qwen, 0.5B to 4B parameters, 4-bit) can suggest a category. It runs on your device with WebLLM on WebGPU, inside a Web Worker, and is downloaded only when you tap Download.
- Suggestions never change totals. An AI or learned guess is stored as a suggestion. It counts only once you accept it.
- Explainable. Every category records why it was applied (a rule, your history, your own choice or a learned word), and the app shows that reason in one line.
- Learns from your fixes. When you fix a payment, the app records its meaningful word (for example
EMERGENCYFUND) against the category you chose. After two consistent fixes it applies that category on its own. It never overrides a choice you made by hand.
Key decisions and trade-offs
1. Read the statement in the browser, not on a server
Decision. The statement is read in the browser and is never uploaded.
Trade-off. Your statement never leaves your device, so there is no server copy of it. The flip side is the next decision: without a server, nothing is shared between your devices.
2. No sign-up, no login, saved only in this browser
Decision. There are no accounts. Your data is saved only in the browser you used.
Trade-off. You can start straight away, with nothing to register. The cost is that your data won't appear on your other phone or computer, and clearing browser data can delete it. That is why the app asks you to save a backup file after your first statement.
3. Four clear categories, and you have the final say
Decision. Every payment lands in one of four categories: Spent, Income, Invested or Moved.
Trade-off. Four categories keep the picture simple enough to read at a glance. Automatic sorting can still get a payment wrong, so you can check and fix anything it gets wrong.
4. Rules first, AI only as a fallback
Decision. Rules and learned words decide whenever they are confident. The AI model is only asked about what is left.
Trade-off. Rules leave more payments unanswered, so you check a few more by hand. In return, every automatic answer is predictable and explainable, and the app works fully on devices that can't run a model.
5. An on-device model, not a cloud AI service
Decision. The AI model runs in your browser, so a payment's description is never sent to an AI provider.
Trade-off. The model is a large one-time download and needs a device with WebGPU. So it is opt-in and checked against the device's capability first. Only one model runs per browser, watchdogs stop a model that hangs, and a model that crashed is not started again automatically.
Privacy and reliability
- No backend and no analytics. A Content Security Policy allows only the app's own files plus the hosts that serve the optional model, and no transaction data goes to them.
- Backups you control. You can save a backup file, optionally encrypted (AES-GCM-256 with a key derived by PBKDF2), or turn on automatic backups to a folder, because browser storage can be cleared.
- Tested in a real browser. The tests use Python and Playwright, in headless Chrome with WebGPU.
Stack
JavaScript (ES modules, no framework) · IndexedDB (Dexie) · pdf.js · PapaParse · WebLLM on WebGPU · Web Workers · Service Worker (PWA) · Web Crypto · Python + Playwright