Basma Data Entry AI
A Python desktop app that turns a folder of scanned employee files and HR spreadsheets into reviewable database records — no server, no live database connection.
Onboarding a workforce into Basma meant retyping hundreds of scanned national IDs, employment contracts and certificates by hand, cross-checked against an HR spreadsheet. This desktop app does that pass instead: point it at a folder, and it classifies and extracts every document, merges the scans with the spreadsheet person by person, and writes one import.sql file for an operator to review before it ever touches the real database.
It is built around a single principle: wrong or invented employee data is worse than no data at all.
The Challenge
Two incomplete sources, an AI that must never guess, and operators who are not engineers.
- A scanned contract and an HR spreadsheet each hold half the record — a contract rarely states the payroll figure, and the sheet has none of the documents
- An AI that hallucinates a national ID number is worse than an AI that returns nothing
- The same person's name, typed into a sheet and read off a scan, routinely differs by a letter or two
- The operator is an HR administrator — the tool has to be a window you point at a folder, not a service to deploy
- Nothing should be able to write to the production database by accident
The Solution
A single extraction pipeline behind a local GUI, where every field carries its own confidence and the only output is a file a human reviews.
- Gemini classifies every PDF page into one of eight document types — national ID, employment contract, no-criminal-record certificate, job application, education certificate, employee photo, passport, other — and groups pages belonging to the same physical document
- Every extracted field is returned as
{value, confidence, source_page}; anything the model cannot read clearly comes backnullrather than guessed - Excel rosters are parsed with no AI call at all, and the correct sheet is chosen by scoring each header row against known employee fields instead of trusting whichever sheet was left active
- Both sources converge on one shape, so a field behaves identically downstream regardless of where it came from
- Cross-source matching runs phone number first, then exact name, then fuzzy name comparison
- Output is a portable
import.sql—INSERT IGNOREfor employees,INSERT … SELECTto resolve document foreign keys by phone rather than a literal id - Reprocessing a person merges field by field and preserves their assigned id, instead of overwriting the folder
- Local-first by dependency:
requirements-desktop.txtinstalls neither Flask nor a MySQL driver, so the desktop build physically cannot open a server or a live connection - The CustomTkinter GUI reports rosters read, PDFs extracted and records merged as it goes, and flags low-confidence fields and unusual page counts for review before the SQL is run
The Basma Platform
Basma ships as four separate products against one backend. Each is its own build, and each one I designed and engineered end to end.
- Mobile app — Flutter, iOS & Android — geofenced clock-in with biometric verification, leave workflows and manager dashboards.
- Marketing site — The public landing page, built around a single conversion path: request a demo.
- Web dashboard — Thirteen admin screens — attendance, payroll, employee records, reports — white-labelled per tenant. (coming soon)
- Desktop data entry — A Python desktop tool that turns scanned files and HR spreadsheets into reviewable database records. (this project)