Status: Archived - no longer actively developed. Published as a portfolio reference.
Full-stack image-identification app built around a Google Gemini vision pipeline, with a custom evaluation harness benchmarking model configurations across accuracy, token usage, and cost.
The product side identifies consumer goods (firearms, knives, music gear) from a photo and returns specs + market pricing. The engineering side is a multi-tier API service with measured model selection - the README below leads with that work.
Vision model benchmarking. Built a 30-image golden dataset and eval harness comparing Gemini configs across resolution and reasoning levels. Results drove the production model choice:
| Config | Avg Accuracy | Avg Tokens | Notes |
|---|---|---|---|
| Flash Low+Med | 87.8% | 1,160 | Production pick - best accuracy/cost ratio |
| Flash High+Med | 85.6% | 2,032 | More tokens, less consistent |
| Lite Low+Med | 83.3% | 834 | Free tier - ~⅓ the token spend |
Tier-based model routing. Free users hit Flash Lite ($0.0011/request), Pro users hit Flash ($0.0029/request). At $10/mo with 20 searches/day, infra cost is ~$1.74/mo per Pro user.
Full-stack ownership. React Native client (Expo), Node/Express API, Postgres, Google OAuth + JWT, tier-based rate limiting, client-side image compression (512px JPEG), search history with thumbnails, eBay/GunBroker pricing integration.
- Backend, eval harness, and web client work end-to-end on a development machine.
- Mobile (iOS/Android native builds) was never completed - Expo dev server only.
- Repo is archived; no support, issues, or PRs.
- User uploads or takes a photo of an item.
- Image is compressed client-side (512px JPEG) and sent to the server.
- Server routes to Gemini Flash (Pro) or Flash Lite (Free) based on user tier.
- Gemini identifies the item - brand, model, specs, confidence score.
- Server queries eBay (and GunBroker, scaffolded) for market pricing.
- Result is cached and stored in search history with a thumbnail.
| Layer | Tech |
|---|---|
| Frontend | React Native + Expo (JavaScript) |
| Backend | Node.js + Express |
| Database | PostgreSQL (Docker locally) |
| Auth | Google OAuth via Expo Auth Session, JWT |
| Vision AI | Google Gemini 3 Flash / 3.1 Flash Lite |
| Pricing | eBay API, GunBroker API |
| Payments | Stripe (scaffolded, incomplete) |
- Firearms - Pistol, Rifle, Shotgun, Revolver
- Knives - Folding, Fixed Blade, Hunting, Tactical, Collectible
- Music Gear - Pedal, Guitar, Bass, Amp, Keyboard, Drum Kit, Microphone
- Other
GearScan/
├── client/ # React Native Expo app
│ ├── app/ # Screens (search, history, account)
│ ├── context/ # Auth state (JWT + user)
│ ├── hooks/ # Google OAuth
│ └── services/ # API client
├── server/
│ ├── src/
│ │ ├── controllers/ # Search endpoint logic
│ │ ├── db/ # pg pool + SQL migrations
│ │ ├── middleware/ # JWT auth, tier-based rate limiting
│ │ ├── routes/ # auth, search, user
│ │ └── services/ # Gemini, eBay, GunBroker integrations
│ └── docker-compose.yml # PostgreSQL container
└── GoldenDataset/ # Evaluation harness
├── labels.json # Dataset schema
├── results/ # Benchmark output
└── gemini.py # Model evaluation script
Note: The dataset images themselves are not committed (copyright + size). The harness, schema, and result summaries are.
Prerequisites: Node.js 18+, Docker, Google Cloud account (Gemini API key), Google OAuth credentials.
# Database
docker compose -f server/docker-compose.yml up -d
# Server
cd server && npm install
# Create server/.env (see .env.example)
npm run dev
# Client
cd client && npm install
# Create client/.env (see .env.example)
npx expo start --clear
# Run benchmark
cd GoldenDataset && python gemini.pyMIT - see LICENSE.