Automating My Weekly Expense Report
Automating My Weekly Expense Workflow
Every week, I used to spend about 20–30 minutes on a task that felt like a waste of productive time: gathering parking receipts, converting images, and manually assembling them into a montage for my expense report. It was a grinding, repetitive process that consistently ate into my productive time.
The workflow was particularly frustrating because of the friction points involved. Specifically dealing with iOS's HEIC format and the sheer number of manual steps required to get a final files ready for payroll.
The Old Way
Before I automated this, the process looked like this:
- Conversion: Since my iPhone saves photos in HEIC format, they are incompatible with the service used in the second step to create a montage of the receipts. For this reason, I would manually convert every single receipt image to jpeg format using a self-hosted instance of ConvertX.
- The Montage: I needed to arrange all these individual photos into a single, clean rectangular grid/montage, which I created using an online tool called photojoiner.
- The PDF Problem: After submitting my expenses via the web portal, I download the official expense report as a PDF. To attach my montage, I would use a free online service called combinepdf to append the image page to the end of the report. Once the PDF was assembled, I email it to our team that handles expenses as a fail-safe.
Using multiple online third-ability tool for this felt incredibly wrong from a privacy perspective. These receipts often contain the last four digits of my credit card and occasionally even my vehicle's license plate. Uploading that data to a random web service is way too invasive and completely unecessary for a weekly expense report.
The Solution: Python Automation
I decided to use some AI-assisted development to engineer a suite of Python scripts to automate as much of this as possible. Since I know the fundementals and can read code better than I can write it, I essentially just spelled out what the code and architechure should look like, referenced similar open source projects (such as PDF Arranger), audited it line-by-line, and tested the end result in various virtual/bare-metal machines. Now, I'm using the tools every week. This new process is offline and always available, regardless of external services (photojoiner, combinepdf, etc.):
make-image-grid.py
An alternative to using PhotoJoiner, this script handles the heavy lifting of the initial preparation. It can take HEIC, HEIF, JPG, JPEG, and PNG images and automatically generate a balanced JPG grid from all the images in a directory. No more manual resizing or dragging images around.
append-image-page.py
CombinePDF alternative: This script takes the downloaded expense report PDF and appends my newly created montage as a US Letter-sized page at the end. Like the grid script, it runs locally to ensure everything stays on my machine.
Experimental: Local Vision Models
The most exciting (and experimental) part of this project is a tool I've been engineering called receipt-processor. This leverages local LLMs with vision capabilities to automate the data extraction portion of the task.
The workflow works like this:
- The AI model extracts the date and total from each individual receipt.
- The tool generates a daily summary in JSON format, automatically adding up the totals for each day of the week.
By default, the processor is configured to use local or private-network endpoints, so even the image processing stage stays entirely within my controlled environment.
Current Status: This part of the process is still experimental, so I always verify the results manually.
The Good: I've found that Gemma 4 26B is remarkably robust; it can even interpret photos that were taken sideways. In contrast, models like Ministral tend to fail in those scenarios. However, when using clear, upright pictures, the Ministral 3B model at only 2.7Gb in size can quite literally blast through images (on my RTX 5080 workstation) at about roughly 2 images per second - with surprising accuracy!
The Bad: The system currently struggles with two main issues:
- Image Quality: Blurry or very dark photos lead to extraction failures.
- Complexity: If there is more than one receipt captured in a single photo, the model fails to parse them correctly.
Conclusion
The result of this automation has been a massive reduction in friction. What used to be a 20–30 minute weekly chore now takes a maximum of 5 minutes. It's a small win, but automating away that kind of work is well worth the effort.
Source Code
The full suite of scripts can be found on GitHub.