| title | Vahi API |
|---|---|
| emoji | 📒 |
| colorFrom | yellow |
| colorTo | blue |
| sdk | docker |
| app_port | 7860 |
| pinned | false |
| license | mit |
| short_description | Vahi backend — FastAPI (Invoice OCR + Fuzzy Lookup). |
वही · your finance toolkit — turn invoice PDFs into Excel, fuzzy-match any two lists. ₹0 / $0 per document.
Live demo: vahi-lemon.vercel.app Backend: vishwas51-vahi-api.hf.space Stress-tested accuracy: 93.1% invoice OCR · 96.4% fuzzy match
Built for finance teams hitting two daily walls:
- Invoice OCR — drop digital + scanned PDFs, get one merged Excel with custom column headers.
- Fuzzy Lookup — match two lists (bank statement → vendor master, etc.) with smart business-name normalization.
Architecture: Next.js frontend (built with Gemini) + FastAPI backend (Python). Both deploy free, both global.
.
├── api.py # FastAPI backend (4 endpoints)
├── modules/ # Pure-Python invoice/fuzzy logic
│ ├── pdf_utils.py
│ ├── invoice_ocr.py
│ ├── fuzzy_lookup.py
│ ├── excel_writer.py
│ ├── column_utils.py
│ └── schema.py
├── requirements.txt # Python deps
├── packages.txt # System deps for HF Spaces (tesseract, poppler)
├── Dockerfile # Backend container
├── vahi-frontend/ # Next.js + Tailwind + shadcn/ui (Gemini-generated)
└── tests/ # Stress test data + benchmark runner
Terminal 1 — backend:
brew install tesseract poppler # macOS; on Linux: apt-get install tesseract-ocr poppler-utils
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
uvicorn api:app --reload --port 8000Sanity-check: curl http://localhost:8000/api/health → {"ok":true,...}.
Terminal 2 — frontend:
cd vahi-frontend
cp .env.example .env.local
npm install
npm run devOpen http://localhost:3000.
The recommended stack:
| Layer | Host | Cost | Why |
|---|---|---|---|
| Frontend (Next.js) | Vercel | Free | Made for Next.js, global CDN, HTTPS, instant |
| Backend (FastAPI + Tesseract) | Hugging Face Spaces (Docker SDK) | Free | 16 GB RAM / 2 vCPU free tier, no sleep, public URL |
- Sign up free at https://huggingface.co/join.
- Create a new Space at https://huggingface.co/new-space:
- Name:
vahi-api - SDK: Docker
- Hardware: CPU basic — Free
- Visibility: Public
- Name:
- Get a write token at https://huggingface.co/settings/tokens.
- Push this repo to that Space:
cd "/Users/vishwaspandey/OCR cum FUZZY LOOKUP" git remote add space https://huggingface.co/spaces/<your-username>/vahi-api git push space main # paste the write token when prompted
- HF reads the
Dockerfileat the repo root, builds the image, and runs it on port7860. - After ~5 min build:
https://<your-username>-vahi-api.hf.space/api/healthreturns{"ok":true}.
The backend listens on
$PORT(default 7860 on HF). If your hosted URL ishttps://abc-vahi-api.hf.space, your API base ishttps://abc-vahi-api.hf.space/api.
- Push the repo to GitHub (so Vercel can read it):
gh repo create vahi --public --source=. --push
- Go to https://vercel.com/new, import the GitHub repo.
- Root Directory:
vahi-frontend(important — Vercel needs to point at the Next.js app). - Environment Variables: add one:
NEXT_PUBLIC_API_BASE = https://<your-username>-vahi-api.hf.space/api - Click Deploy. ~2 minutes.
- Vercel gives you
https://vahi-<random>.vercel.app. Anyone in the world can use it.
Edit the HF Space's Settings → Variables and add:
VAHI_ALLOWED_ORIGINS=https://vahi-<random>.vercel.app,https://*.vercel.app,http://localhost:3000
Restart the Space. Now only your frontend (and localhost dev) can hit the API.
| Host | Free tier | Notes |
|---|---|---|
| Hugging Face Spaces (Docker) | 16 GB RAM / 2 vCPU, no sleep | Recommended. No credit card. |
| Render | 512 MB RAM, sleeps after 15 min | Cold start hurts UX. |
| Fly.io | 3 × 256 MB VMs, 160 GB transfer | Tight RAM for OCR. |
| Google Cloud Run | 2M req/mo + 360k GB-s free | Scales to zero. Cold starts. |
| Oracle Cloud Free Forever | 4 ARM cores, 24 GB RAM, always-on | Best specs but account approval is slow. |
For "everyone in the world, free", HF Spaces wins. Period.
| Method | Path | Purpose |
|---|---|---|
GET |
/api/health |
Liveness check. |
POST |
/api/extract |
Multipart files. Returns { jobId }. |
GET |
/api/jobs/{id} |
Returns { status, progress, invoices[] }. |
POST |
/api/excel |
{ invoices, schema } → .xlsx blob. |
POST |
/api/match |
{ source_b64, target_b64, src_col, tgt_col, threshold, learned } → { matched, unmatched, matchRate, learnedCount }. |
OpenAPI / Swagger UI is auto-generated at /docs.
Run python tests/run_stress.py from the repo root.
| Module | Accuracy | Notes |
|---|---|---|
| Invoice OCR | 93.1% | 5 layouts × digital + scanned. Vendor name 100%. |
| Fuzzy Lookup | 96.4% | 6 distortion classes + 20 distractors. 0 false positives. |
Performance: 25 ms per digital invoice, ~7 s per scanned, 0.4 ms per fuzzy row.
- The backend never writes uploaded PDFs to disk.
- Job results are kept in-memory for 30 min, then garbage-collected.
- For sensitive invoices, self-host the Docker container behind your VPN.
MIT.