Skip to content
mk
All work

Final year project · NUST SEECS

Finasaan

A financial literacy platform for Pakistan with market data, funds, insurance, tax and budgeting, plus a chatbot that answers from real filings.

Key decisions

  1. Split ingestion and user traffic into separate Workers, so a slow PDF parse never sits in front of a request.
  2. Parsed PSX's daily PDFs by text position, because plain text extraction merges the columns.
  3. Normalized fiscal periods and company names inside the retrieval tools instead of hoping the model would match them.
  4. Let the model parse budget questions but compute every total in code.
Role
One of three engineers. Built the data ingestion pipelines, the first version of the chatbot and most of its knowledge tools, budgeting, portfolios and a large part of the dashboard.
When
2025 to 2026
Where
NUST SEECS
Stack
Next.js, TypeScript, Hono, Cloudflare Workers, Supabase, PostgreSQL, pgvector, Workers AI, AI Gateway, Groq, Gemini
Finasaan landing page. The finasaan wordmark, an Available in late 2025 badge, the headline Understand your money, change your future and an email waitlist form on a black background.

Finasaan was our final year project at NUST, built by three of us across the 2025 to 2026 academic year. A lot of young people in Pakistan want to invest but don't know where to start, and the information they'd need is scattered across PSX PDFs, fund house sites, insurance brochures and FBR circulars. A survey we ran with 200+ people, mostly 18 to 24, backed that up. Not knowing where to start came up far more often than not having the money.

Who did what

There were three of us. One teammate owned the infrastructure and dev tooling and later rebuilt the chatbot around tool calling, and another revamped the landing page. I built the first version of the chatbot and most of the data side: every ingestion pipeline, most of the knowledge tools the chatbot calls, budgeting, portfolios and watchlists, login and onboarding and a large part of the dashboard.

The browser talks to Core, a Next.js app running as a Cloudflare Worker. Core calls Spine, the Hono API worker, over a service binding. Spine reads and writes Supabase Postgres with pgvector and calls language models through Cloudflare AI Gateway, which routes to Groq and Gemini, with embeddings from Workers AI. A separate worker, Marrow, ingests PSX closing rate PDFs and trade ticks, mutual fund NAVs from Sarmaaya, insurer and FBR PDFs and news feeds, then parses, hashes, chunks and embeds them into the same database.

Three Workers, one Postgres database. Ingestion and user traffic never share a worker.

Architecture

Everything runs on Cloudflare. The Next.js frontend is itself a Worker and reaches the API over service bindings rather than public HTTP. Spine is the user facing API, built on Hono: auth, portfolios, budgets and the chatbot. Marrow is an internal worker for ingestion and admin jobs, so a slow PDF parse never sits in front of a user request. Both share one Supabase Postgres database with pgvector.

Language models go through Cloudflare AI Gateway with provider keys stored on the gateway, so a request can switch between Groq hosted Llama and Gemini models without the app holding any provider keys. Embeddings come from Workers AI.

Getting the data in

There's no clean API for most Pakistani financial data. Each source needed its own pipeline, all of them running on Workers where things like pdf.js page rendering aren't available.

  • PSX publishes a closing rate PDF every trading day. Plain text extraction merges its columns, so the parser works from text positions, groups items into rows by their Y coordinate and skips the bond and futures sections. Backfills skip weekends and are idempotent per date.
  • Daily OHLCV for each company is aggregated in memory from intraday trade ticks with bounded concurrency, falling back to the end of day endpoint for instruments that have no intraday data. Ticks are never stored.
  • Mutual funds and about five years of NAV history per fund come from Sarmaaya's API, paginated and written in batches.
  • Insurance policy documents are fetched, cleaned, hashed with SHA-256 so reruns don't duplicate anything, split on paragraph boundaries and embedded into pgvector with an HNSW cosine index. Urdu script is stripped before embedding since the embedding model is English only, and search is filtered by company so answers don't blend insurers.
  • FBR tax guidance goes through Workers AI document conversion with a fallback to plain PDF text, then into overlapping chunks.
  • A daily cron pulls economic news from RSS feeds and uses a model to drop anything that isn't actually about the economy.

The chatbot

I built the first version of FinasaanGPT, streaming answers grounded in our own documents. It was later rebuilt around tool calling, and I wrote most of the knowledge tools it calls now.

The hard part of retrieval over Pakistani filings is that nothing is named consistently. A question about Q1 2026 has to match periods stored as 2026-03, 2026-03-31 or Q12026, and HBL has to match Habib Bank Limited. The tools expand a fiscal period into every equivalent form, resolve company names and tickers against the companies table and fall back in stages: company plus period, then company alone with a note about which periods exist, then raw document chunks when no structured table matches.

Some fixes only showed up with real traffic. Groq rejects a conversation that contains a tool call with no result, which is exactly what an interrupted stream leaves behind, so history is sanitized before every turn. Partial answers are saved even if the stream dies, so a question doesn't vanish on reload.

Your own documents

Users can upload PDFs to ask about. Each page is classified. Prose goes straight to chunking and embedding. Table heavy pages go to Llama 3.3 70B in JSON mode, which returns structured tables plus the surrounding prose. Rendering pages to images isn't possible on Workers, so the model works from whatever text could be pulled off the page.

Files are hashed so the same PDF isn't processed twice, and extracted text is scrubbed of null bytes and lone UTF-16 surrogates, which PDFs leak surprisingly often and Postgres refuses to store.

Onboarding screen asking How would you describe your financial knowledge, with Beginner, Intermediate and Advanced cards.Onboarding screen asking What would you like to learn about, with topic chips such as Mutual Funds, Stock Market and PSX, ETFs and Taxation.
Onboarding asks for knowledge level and interests so learning and chat can pitch explanations at the right depth.

The rest of the product

  • Budgets with categories, transactions and savings goals. Questions like how much did I spend on food last month are parsed by a model into a structured query, but the totals are computed in code, so the model explains numbers it didn't make up. New transactions get a suggested category with a confidence score.
  • Portfolios, holdings and watchlists on top of the PSX data, with stock and fund pages, price charts and technical indicators.
  • Salary tax, taxation and returns calculators, insurance and takaful browsing and learning journeys with modules and quizzes.
  • Schema changes live as migrations in their own repo. Each service deploys to Cloudflare from GitHub Actions with a separate preview environment.