Retail inventory tracker with AI-powered vision and demand forecasting
Built for UGAHacks 11 | First Timer
Braxton Scarbrough, Noah Piontek, Zachary Locker, Tyler Price
Storacle helps retail businesses track inventory with just two photos per day (morning and end-of-day). Using Google Gemini Vision API, it automatically counts products and forecasts stockouts to suggest optimal reorder timing.
Core Features:
- Image-based inventory counting via Gemini Vision
- Time-series demand forecasting
- Stockout prediction and reorder suggestions
- Visual dashboard for inventory trends
- Take Photos: Capture inventory images (AM and EOD)
- Upload: POST to
/snapshots/uploadwith image and time - Process: Gemini Vision counts products automatically
- Analyze: View trends and forecasts on dashboard
- Reorder: Get stockout alerts and reorder timing suggestions
- Choosing how to store data
- Getting Gemini API to work with free tier
- Managing dependencies across teammates without containers
- Parsing data from ML model (dates wouldn't format as intended from docs)
- Frontend: Next.js (TypeScript, Tailwind CSS)
- Backend: FastAPI (Python)
- Computer Vision: Google Gemini API
- Database: SQLite (SQLAlchemy ORM)
- Forecasting: Darts, scikit-learn
- Deployment: Vercel (frontend), Railway/Render (backend)
- Python 3.12+
- Node.js 18+
- Google Gemini API key (Get one here)
-
Navigate to the backend directory:
cd backend -
Create and activate virtual environment:
python3 -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install --upgrade pip pip install -r requirements.txt
-
Configure environment variables:
cp .env.example .env
Edit
.envand add your Gemini API key:GEMINI_API_KEY=your_actual_key_here -
Run the backend server:
uvicorn main:app --reload --port 8000
The API will be available at
http://localhost:8000
-
Navigate to the frontend directory:
cd frontend -
Install dependencies:
npm install
-
Configure environment variables:
cp .env.local.example .env.local
The default configuration should work for local development:
NEXT_PUBLIC_API_URL=http://localhost:8000 -
Run the development server:
npm run dev
The app will be available at
http://localhost:3000
All inventory data flows into a single SQLite database (inventory.db) through three paths:
Photo upload ──→ Gemini Vision ──→ JSON ──→ DB
Manual entry ────────────────────────────→ DB
Manual edit ───────────────────────────→ DB
snapshots — One row per inventory check (AM opening or EOD closing).
| Column | Type | Description |
|---|---|---|
id |
Integer (PK) | Auto-incremented ID |
timestamp |
DateTime | When the snapshot was taken |
time_of_day |
String | "AM" or "EOD" |
store_name |
String | Store identifier (e.g. "downtown_grocery") |
inventory_counts — One row per product type per snapshot.
| Column | Type | Description |
|---|---|---|
id |
Integer (PK) | Auto-incremented ID |
snapshot_id |
Integer (FK) | References snapshots.id |
product_type |
String | e.g. "canned_beans", "pasta" |
count |
Integer | Number of items counted |
All stores share one database, filtered by store_name. Pass ?store_name=my_store on GET requests or include store_name in POST/form data.
When a photo is uploaded, Gemini Vision analyzes the shelf image and returns a JSON array of product counts:
[{"product_type": "canned_beans", "count": 12}, {"product_type": "pasta", "count": 8}]Each item becomes an InventoryCount row linked to the snapshot.
Once the backend is running:
- Swagger UI: http://localhost:8000/docs
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/snapshots?store_name=X |
List recent snapshots (optionally filter by store) |
POST |
/snapshots/upload |
Upload shelf photo → Gemini counts → DB (form: file, time_of_day, store_name) |
POST |
/snapshots/manual |
Manually create a snapshot with counts (JSON body) |
PUT |
/snapshots/{id}/counts |
Edit counts on an existing snapshot (JSON body) |
GET |
/forecast |
Demand forecast and reorder suggestions |
curl -X POST http://localhost:8000/snapshots/manual \
-H "Content-Type: application/json" \
-d '{
"time_of_day": "AM",
"store_name": "downtown_grocery",
"counts": [
{"product_type": "canned_beans", "count": 45},
{"product_type": "pasta", "count": 30}
]
}'curl -X PUT http://localhost:8000/snapshots/1/counts \
-H "Content-Type: application/json" \
-d '[{"product_type": "canned_beans", "count": 50}]'storacle/
├── backend/ # FastAPI service
│ ├── main.py # API routes, Gemini integration
│ ├── models.py # SQLAlchemy ORM models (Snapshot, InventoryCount)
│ ├── database.py # Database configuration
│ ├── requirements.txt # Python dependencies
│ ├── .env.example # Environment template
│ └── setup.sh # Automated setup script
├── frontend/ # Next.js application
│ ├── app/ # Next.js App Router pages
│ ├── lib/ # Utilities and API client
│ └── .env.local.example
├── CLAUDE.md # Project guidelines for AI assistance
└── INSTRUCTIONS.md # Detailed setup instructions
| Variable | Description | Required |
|---|---|---|
GEMINI_API_KEY |
Google Gemini API key for vision processing | Yes |
| Variable | Description | Default |
|---|---|---|
NEXT_PUBLIC_API_URL |
Backend API base URL | http://localhost:8000 |
- shadcn/ui – React component library
- Shadcn MCP Server – Cursor MCP that helps with shadcn components
MIT License - Built for UGAHacks 11
- Google Gemini API for vision capabilities
- UGAHacks organizing team