Athan Notes
Speak a note in Burmese and it lands in Notion, transcribed, summarised, categorised and tagged.
VIEW CODE ↗2026
Overview
Athan Notes is an installable web app I built on my own. You record a voice note in the browser, and Gemini turns it into a clean Burmese transcript, a one-sentence summary, a category, English tags and a title. The result is saved to a Notion database automatically. The audio is processed in memory and never stored.
At a glance
- App
- Next.js 16, React 19, TypeScript
- AI
- Gemini 2.5 Flash, with two fallback models
- Saves to
- A Notion database, through the official client
- Login
- bcrypt password, iron-session cookie
- Install
- Progressive web app with an offline page
- Tests
- Jest and Testing Library
From voice to Notion
- Record in the browser
- POST /api/process-audio
- Gemini 2.5 Flash
- Zod checks the JSON
- Page created in Notion
- Result shown to you
What it shows
- One prompt, five jobs. The prompt asks Gemini to correct and tidy the Burmese transcript, write a short summary, pick a category, extract English tags and give a title in the language that was spoken. It answers as JSON.
- Model fallback. Three Gemini models are tried in order. A 404, 429, 500 or 503 error, or a 60 second timeout, moves on to the next model.
- Validated output. The reply is checked with a Zod schema that is built from the category config. A category that is not on the list, an empty transcript or too many tags is rejected.
- Categories you can change. config/categories.json holds each category with an icon and a description. The descriptions are fed into the prompt, so changing the file changes how notes are sorted.
- Long notes fit in Notion. The transcript is split into chunks of at most 1,900 characters before it is written to the page, and the summary is cut at a word or Burmese sentence break.
- Login without a user database. The username and a bcrypt hash live in environment variables. A successful login sets an encrypted, httpOnly iron-session cookie, and a proxy redirects every other visitor to the login page. Login attempts are limited to 5 per 15 minutes.
- Guard rails on upload. Only common audio formats up to 50 MB are accepted, and the browser gives up after 120 seconds.
How it works
- The browser records audio with MediaRecorder (WebM with Opus). You can pause and resume.
- The file is posted to /api/process-audio, which first checks that you are logged in and that the file is a supported audio type and size.
- The audio is sent to Gemini as base64 with the prompt. The JSON reply is parsed and validated.
- A new page is created in the Notion database with the title, category, tags, summary and full transcript, and the page link comes back to the app.
Use it
The API
POST /api/process-audio (login required)
body: audio file (multipart)
returns: { title, content, summary, category, tags, categoryIcon, notionUrl }Run it locally
npm install
npm run generate-secret
npm run hash-password
cp .env.example .env.local # add the Gemini and Notion keys
npm run dev