AI-powered multi-destination trip planner — enter your stops, pick an algorithm, get the optimal route instantly.
Live features
- Three AI routing algorithms (Greedy, A*, TSP) with side-by-side comparison
- Interactive Leaflet map with real OpenStreetMap tiles — no API key required
- Free geocoding via Nominatim (OpenStreetMap)
- Day-wise itinerary splitting (configurable km-per-day budget)
- Full light / dark theme with zero-flash persistence
- Docker-first deployment — one command to run everything
- Architecture
- Project Structure
- Local Development
- Docker Deployment
- API Reference
- Algorithms
- Configuration
- Tech Stack
Browser ──(Next.js 14)──► FastAPI (port 8000)
│
sys.path inject
│
ai-engine/
┌─────────┴──────────┐
greedy/ algorithms/
astar/ utils/
tsp/
The backend and ai-engine are separate Python packages kept in the same monorepo. The backend injects the ai-engine/ directory onto sys.path at startup so the algorithms can be imported without an install step.
routegenius-ai/
│
├── frontend/ # Next.js 14 (App Router)
│ ├── app/
│ │ ├── globals.css # Design tokens + all component CSS
│ │ ├── layout.tsx # Google Fonts, theme-flash prevention
│ │ └── page.tsx # View state machine (home→input→results)
│ ├── components/
│ │ ├── HomePage.tsx
│ │ ├── InputPage.tsx
│ │ ├── Map/
│ │ │ ├── MapView.tsx # Dynamic-import wrapper (ssr:false)
│ │ │ ├── LeafletMap.tsx # react-leaflet implementation
│ │ │ ├── SvgFallback.tsx
│ │ │ ├── RouteLayer.tsx
│ │ │ └── Marker.tsx
│ │ ├── Results/
│ │ │ ├── ResultsPage.tsx
│ │ │ ├── ComparisonPage.tsx
│ │ │ ├── RouteSummary.tsx
│ │ │ ├── ComparisonTable.tsx
│ │ │ └── Itinerary.tsx
│ │ ├── Input/
│ │ │ ├── LocationInput.tsx
│ │ │ └── LocationList.tsx
│ │ └── UI/
│ │ ├── TopNav.tsx
│ │ ├── Button.tsx
│ │ ├── Card.tsx
│ │ └── Dropdown.tsx
│ ├── hooks/
│ │ ├── useRoute.ts # Geocoding + API calls
│ │ └── useMap.ts # Bounds fitting helper
│ ├── lib/
│ │ ├── api.ts # optimizeRoute / compareRoutes
│ │ ├── constants.ts # ALGO_INFO, TRAVEL_MODES
│ │ └── helpers.ts # geocodeLocation, toggleTheme, formatters
│ └── types/index.ts # TypeScript types (mirrors backend Pydantic)
│
├── backend/ # FastAPI
│ ├── app/
│ │ ├── core/config.py # Settings (CORS, ai_engine_path)
│ │ ├── models/ # Pydantic request / response models
│ │ ├── routes/ # /optimize-route /compare-routes
│ │ ├── services/ # route_service.py (orchestrator)
│ │ └── main.py # Lifespan, CORS, /health
│ ├── run.py
│ ├── requirements.txt
│ └── Dockerfile
│
├── ai-engine/ # Pure-Python algorithm core
│ ├── algorithms/
│ │ ├── greedy.py # Nearest-neighbour O(n²)
│ │ ├── astar.py # A* with MST heuristic
│ │ └── tsp.py # Brute-force ≤8 nodes, NN+2-opt otherwise
│ ├── utils/
│ │ ├── distance.py # Haversine formula
│ │ ├── graph.py # Adjacency-matrix builder
│ │ └── itinerary.py # Day-wise km-packing
│ ├── tests/
│ │ ├── test_greedy.py
│ │ ├── test_astar.py
│ │ └── test_tsp.py
│ └── benchmark.py
│
├── shared/
│ └── types/
│ ├── route.ts # Canonical TypeScript types
│ └── route.py # Canonical Pydantic models
│
├── scripts/
│ ├── setup.sh # Install all deps (run once)
│ └── run-all.sh # Start backend + frontend in parallel
│
└── docker-compose.yml
- Node.js ≥ 18
- Python ≥ 3.10
- npm ≥ 9
# Clone the repo and install everything
git clone <repo-url>
cd routegenius-ai
bash scripts/setup.shsetup.sh runs npm install --legacy-peer-deps for the frontend and pip install -r requirements.txt for both the backend and ai-engine.
bash scripts/run-all.shThis starts the backend on http://localhost:8000 and the frontend on http://localhost:3000 in parallel. Press Ctrl+C once to cleanly shut both down.
# Backend
cd backend
python run.py
# Frontend (separate terminal)
cd frontend
npm run devcd ai-engine
python -m pytest tests/ -vcd ai-engine
python benchmark.pydocker compose up --buildThe frontend will wait for the backend health check to pass before starting.
| Service | URL |
|---|---|
| Frontend | http://localhost:3000 |
| Backend | http://localhost:8000 |
| API docs | http://localhost:8000/docs |
docker compose downIf you deploy the backend at a different host/port, pass it as a build argument:
NEXT_PUBLIC_API_URL=https://api.example.com docker compose up --buildAll endpoints accept and return application/json.
Returns the service status and a list of loaded algorithm modules.
Response
{
"status": "ok",
"algorithms_loaded": ["greedy", "astar", "tsp"]
}Optimise a list of locations with a single algorithm.
Request body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
locations |
Location[] (2–20 items) |
✓ | Ordered list of {lat, lng} objects |
|
algorithm |
"greedy"│"astar"│"tsp" |
✓ | Algorithm to use | |
travel_mode |
"walk"│"car"│"transit" |
"car" |
Informational only in current version | |
max_daily_km |
number (≥ 0) |
0 |
If > 0, splits route into daily segments |
Example
{
"locations": [
{"lat": 48.8566, "lng": 2.3522},
{"lat": 51.5074, "lng": -0.1278},
{"lat": 52.3676, "lng": 4.9041}
],
"algorithm": "astar",
"travel_mode": "car",
"max_daily_km": 600
}Response
{
"route": [0, 2, 1],
"total_distance": 892.4,
"computation_time": 0.0003,
"nodes_explored": 6,
"solver_used": null,
"itinerary": [
{"day": 1, "stops": [0, 2], "distance_km": 430.1},
{"day": 2, "stops": [2, 1], "distance_km": 462.3}
]
}Run all three algorithms on the same input and return a side-by-side comparison.
Request body — same fields as /optimize-route except algorithm is omitted.
Response
{
"greedy": { ...RouteResult },
"astar": { ...RouteResult },
"tsp": { ...RouteResult },
"summary": {
"best_algorithm": "tsp",
"best_distance_km": 891.2,
"distances": {"greedy": 920.1, "astar": 892.4, "tsp": 891.2},
"fastest_algorithm": "greedy",
"computation_times": {"greedy": 0.00008, "astar": 0.0003, "tsp": 0.0012}
}
}Starts from the first location and repeatedly visits the closest unvisited node.
- Time complexity: O(n²)
- Space complexity: O(n)
- Best for: Fast approximations on large sets; usually within 20–25 % of optimal
- Implementation:
ai-engine/algorithms/greedy.py
Uses f(n) = g(n) + h(n) where:
g(n)= total distance travelled so farh(n)= Minimum Spanning Tree (MST) of unvisited nodes (admissible lower bound)
Expands the most promising partial route at each step.
- Time complexity: O(n! / pruned) — exponential worst case, much better with pruning
- Space complexity: O(n · 2ⁿ) in the state space
- Best for: Near-optimal routes when accuracy matters more than raw speed
- Implementation:
ai-engine/algorithms/astar.py
Two-mode solver that automatically selects based on input size:
| Nodes | Solver | Strategy |
|---|---|---|
| ≤ 8 | Brute force | Enumerate all n! permutations, pick shortest |
| > 8 | NN + 2-opt | Multi-start nearest-neighbour followed by 2-opt local search |
- Best for: Exact optimality on small sets; high-quality heuristic on large sets
- Implementation:
ai-engine/algorithms/tsp.py
| Variable | Default | Description |
|---|---|---|
AI_ENGINE_PATH |
Auto-detected from __file__ |
Absolute path to the ai-engine/ directory. Set automatically in Docker. |
CORS_ORIGINS |
http://localhost:3000 |
Comma-separated list of allowed origins |
ENV |
development |
production disables debug logging |
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_API_URL |
http://localhost:8000 |
Backend base URL (baked into the Next.js build) |
| Layer | Technology |
|---|---|
| Frontend | Next.js 14, TypeScript, CSS custom properties |
| Map | react-leaflet + OpenStreetMap (no API key) |
| Geocoding | Nominatim / OpenStreetMap (no API key) |
| Icons | lucide-react |
| Backend | FastAPI, Pydantic v2, Uvicorn |
| AI Engine | Pure Python — no ML libraries |
| Deployment | Docker, docker-compose |