Automated PDF bank statement parsing, transaction categorization, and Excel export — powered by LLM.
- PDF Parsing — Extracts transactions from PDF bank statements using text extraction (pypdfium2) + LLM structured parsing (GPT-5-mini)
- Balance Verification — Mathematically corrects debit/credit assignments using running balance checkpoints (minimum-flip algorithm)
- AI Categorization — Batch-categorizes transactions into accounting categories (Office, Travel, Meals, etc.) with confidence scores
- Excel Export — Generates formatted
.xlsxwith transactions sheet (low-confidence rows highlighted) and category summary - Web UI — Streamlit app with password protection, progress tracking, and interactive results
- Cross-page Handling — Correctly handles transaction groups that span PDF page boundaries
PDF Upload
│
▼
parser.parse_statement()
├── pypdfium2: extract text from each page
├── GPT-5-mini: parse text → structured transactions (JSON)
└── _fix_debit_credit(): balance-based correction across all pages
│
▼
categorizer.categorize_transactions() ← optional
└── GPT-5-mini: batch classify → category + confidence + reasoning
│
▼
writer.write_excel()
└── openpyxl: Transactions sheet + Summary sheet → .xlsx
| Module | Purpose |
|---|---|
models.py |
Pydantic data models (RawTransaction, CategorizedTransaction, etc.) |
parser.py |
PDF text extraction + LLM parsing + balance verification |
categorizer.py |
LLM-based transaction categorization in batches |
writer.py |
Excel report generation with openpyxl |
app.py |
Streamlit web UI |
cli.py |
Command-line interface |
pipeline.py |
End-to-end pipeline orchestration |
config.py |
Environment config (API keys, models, thresholds) |
# Install
pip install -e ".[dev]"
# Configure
cp .env.example .env
# Edit .env with your OpenAI API key:
# OPENAI_API_KEY=sk-...
# Streamlit password (optional)
mkdir -p .streamlit
echo 'password = "your-password"' > .streamlit/secrets.toml| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY |
— | OpenAI API key (required) |
OPENAI_MODEL |
gpt-5-mini |
Model for categorization |
PARSER_MODEL |
gpt-5-mini |
Model for PDF parsing |
streamlit run src/bookkeeping_agent/app.pyOpen http://localhost:8501, log in, upload a PDF bank statement, and download the categorized Excel.
Features:
- Toggle AI categorization on/off (uncategorized mode exports raw transactions only)
- Real-time progress bar for parsing and categorization steps
- Interactive table with confidence scores and category summary
bookkeeping-agent data/input/statement.pdf
bookkeeping-agent data/input/statement.pdf -o output.xlsxPDF text extraction loses column alignment, making it hard for LLMs to determine debit vs. credit. The parser uses a mathematical post-processing step:
- LLM makes a best-guess debit/credit assignment for each transaction
- Transactions are grouped by balance checkpoints (where the running balance is shown)
- For each group, the algorithm checks if the LLM's assignment produces the correct balance change
- If not, it finds the minimum number of transactions to flip (debit↔credit) using combinatorial search
- Budget-capped at 500K combinations to stay practical for large statements
This runs across all pages at once, correctly handling transaction groups that span page boundaries.
# Run tests
pytest -v
# Lint
ruff check src/ tests/
# Run with debug logging
LOGLEVEL=DEBUG bookkeeping-agent data/input/statement.pdf- Python 3.11+
- pypdfium2 — PDF text extraction
- OpenAI API (GPT-5-mini) — LLM parsing & categorization
- Pydantic v2 — data models
- openpyxl — Excel generation
- Streamlit — web UI
- pandas — data display in UI