Real-time hazard detection through crowdsourced image intelligence and AI classification.
- Backend: Flask REST API (Python) - Port 5000
- Frontend: Next.js (React/TypeScript) - Port 3000
- Database: SQLite (default) or PostgreSQL/MySQL via DATABASE_URL
- AI Classification: Roboflow disaster detection models
- Geocoding: Google Maps Geocoding API
📌 IMPORTANT: The Flask backend (
app.py) only runs the API. To see the full UI, you need to run both the backend AND frontend together.
# Using Python script (works on all platforms)
python run.py
# OR using bash script (Mac/Linux)
./start.shThis will:
- ✅ Start the Flask API backend on http://localhost:5000
- ✅ Install Next.js dependencies if needed
- ✅ Start the Next.js frontend on http://localhost:3000
- 🌐 Open http://localhost:3000 in your browser to see the UI
# Activate virtual environment (if using one)
source venv/bin/activate # On Windows: venv\Scripts\activate
# Start Flask server
python app.pyThe API will be available at http://localhost:5000
cd haven-frontend
# Install dependencies (first time only)
npm install
# or
pnpm install
# or
yarn install
# Start development server
npm run dev
# or
pnpm dev
# or
yarn devThe frontend will be available at http://localhost:3000
# Create virtual environment (recommended)
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install Python dependencies
pip install -r requirements.txtcd haven-frontend
npm installpython init_db.py
python seed_db.pyCreate a .env file in the root directory:
cp env.example .envEdit .env and set the following (optional for testing):
# Flask Configuration
SECRET_KEY=your-secret-key-here
DEBUG=True
# Database (SQLite by default)
DATABASE_URL=sqlite:///haven.db
# CORS
FRONTEND_ORIGIN=http://localhost:3000
# Roboflow API (optional - fallback available)
ROBOFLOW_API_KEY=your-roboflow-api-key
ROBOFLOW_MODEL_URL=https://detect.roboflow.com/your-model/version
# Google Maps API (optional - for geocoding)
GOOGLE_MAPS_API_KEY=your-google-maps-api-keyThe frontend .env.local will be created automatically by run.py, or create it manually:
cd haven-frontend
echo "NEXT_PUBLIC_API_BASE_URL=http://localhost:5000" > .env.local
echo "NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=your-key-here" >> .env.localHAVEN/
├── app/
│ ├── __init__.py # Application factory
│ ├── config.py # Configuration classes
│ ├── models.py # SQLAlchemy models
│ ├── routes.py # API routes/endpoints
│ └── utils/
│ ├── __init__.py
│ ├── distance.py # Haversine distance calculations
│ ├── geocode.py # Google Maps geocoding
│ └── roboflow.py # Roboflow image classification
├── haven-frontend/ # Next.js frontend
├── uploads/ # Uploaded images directory
├── app.py # Main application entry point
├── run.py # Run both backend and frontend
├── start.sh # Bash script to start both servers
├── init_db.py # Database initialization script
├── seed_db.py # Seed demo data
├── requirements.txt # Python dependencies
├── env.example # Environment variables template
└── README.md
GET /health- Health check endpoint
POST /reports- Create a hazard report- multipart/form-data: image, description, address, latitude, longitude, user_external_id, source
- Returns: report, incident, and classification results
GET /incidents- List all incidents- Query params:
status(verified/unverified),limit(default: 100)
- Query params:
GET /incidents/<id>- Get a single incident by ID
GET /safe-zones- List safe zones- Query params:
active(true/false, default: true)
- Query params:
POST /safe-zones- Create a new safe zone- JSON body: name (required), address (required), latitude (optional), longitude (optional), accessible (optional, default: true)
- If latitude/longitude are provided, they will be used; otherwise, address will be geocoded
GET /route?fromLat=<lat>&fromLng=<lng>- Get route to nearest safe zone- Returns: safe zone info and Google Maps directions URL
GET /uploads/<filename>- Serve uploaded images
- Accepts image uploads via multipart/form-data
- Uses Roboflow API for hazard classification
- Supports fallback classification when API is unavailable
- Maps classification results to hazard types and severities
- Supports latitude/longitude coordinates
- Supports address geocoding via Google Maps API
- Optional reverse geocoding for coordinates
- Groups reports into incidents based on:
- Distance threshold (400m default)
- Time window (12 hours default)
- Hazard type matching
- Automatically creates new incidents when no match is found
- Incidents are verified when 2+ distinct users report them
- Prevents false positives through multi-source verification
- Status automatically updates from "unverified" to "verified"
- Calculated based on severity:
- Low: 100m
- Medium: 300m
- High: 1000m
- Critical: 1500m
- Finds nearest active safe zone using Haversine distance
- Returns Google Maps directions URL
- Supports accessible/non-accessible zones
id(int, primary key)external_id(string, unique) - Frontend or device IDcreated_at(datetime)
id(int, primary key)hazard_type(string)severity(string) - low, medium, highstatus(string) - unverified, verifiedlatitude(float)longitude(float)address(string, nullable)impact_radius_m(float) - in meterscreated_at(datetime)
id(int, primary key)incident_id(foreign key)user_id(foreign key, nullable)source(string) - citizen, devicehazard_type(string)severity(string)confidence(float)description(text, nullable)latitude(float)longitude(float)address(string, nullable)image_url(string)created_at(datetime)
id(int, primary key)name(string)address(string)latitude(float)longitude(float)accessible(boolean)active(boolean)created_at(datetime)
# Run both servers
python run.py
# OR run separately
# Terminal 1: Backend
python app.py
# Terminal 2: Frontend
cd haven-frontend
npm run dev# Initialize database
python init_db.py
# Seed demo data
python seed_db.py
# Reset database (WARNING: deletes all data)
# Edit init_db.py to uncomment db.drop_all()
python init_db.py# Health check
curl http://localhost:5000/health
# List incidents
curl http://localhost:5000/incidents
# Create safe zone
curl -X POST http://localhost:5000/safe-zones \
-H "Content-Type: application/json" \
-d '{"name": "Test Zone", "address": "New York, NY"}'
# Get route
curl "http://localhost:5000/route?fromLat=40.758&fromLng=-73.9855"- Make sure you've run
npm installin thehaven-frontenddirectory - Make sure you've run
pip install -r requirements.txtfor Python dependencies
- Make sure Flask is running on port 5000
- Check that
NEXT_PUBLIC_API_BASE_URL=http://localhost:5000inhaven-frontend/.env.local - Check browser console for CORS errors
- Stop other processes using port 5000 or 3000
- Or change the ports in
app.pyandhaven-frontend/package.json
- Run:
python init_db.py - Check database file permissions
- Check
.envfile exists and has correct keys - Fallback behavior available for testing without keys
| Variable | Description | Required | Default |
|---|---|---|---|
SECRET_KEY |
Flask secret key | No | dev-secret-key-change-in-production |
DATABASE_URL |
Database connection URL | No | sqlite:///haven.db |
FRONTEND_ORIGIN |
CORS allowed origins | No | * |
ROBOFLOW_API_KEY |
Roboflow API key | No* | - |
ROBOFLOW_MODEL_URL |
Roboflow model URL | No* | - |
GOOGLE_MAPS_API_KEY |
Google Maps API key | No* | - |
*Required for full functionality, but fallback behavior available
- See
START_HERE.mdfor a quick start guide - See
QUICKSTART.mdfor API usage examples
MIT License