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 |