Real-time maritime vessel tracking system with AI-powered assistance and intelligent port destination decoding
Live Demo β’ API Documentation β’ Video Demo (Under Development) β’ Report Bug
- Overview
- Key Features
- The Problem We Solve
- System Architecture
- Technology Stack
- Data Flow
- Getting Started
- Project Structure
- API Endpoints
- Deployment
- Contributing
- License
- Acknowledgments
Live Ship Vessel Tracker is a comprehensive full-stack maritime tracking application that provides real-time vessel monitoring, intelligent destination decoding, and AI-powered maritime assistance. Built with modern web technologies and designed for scalability, this system demonstrates advanced data processing, API integration, and real-time data visualization.
- Intelligent AIS Destination Decoding - Transforms messy, unpredictable AIS destination codes into clean, readable port names and countries
- Batch Processing - Track up to 20 vessels simultaneously with a single request
- AI-Powered Chatbot (COMPASS) - Get instant information about vessels, ports, and maritime routes using Google's Gemini AI
- Real-Time Caching - Redis-powered caching system reduces API calls by 80-90% and improves response times
- Interactive Mapping - Mapbox integration with custom markers for vessels and destination ports
-
Single Vessel Tracking
- Search by IMO number
- View current position on interactive map
- See detailed vessel specifications
- Track destination port with coordinates
- Real-time navigation status
-
Batch Vessel Search
- Process up to 20 vessels simultaneously
- Bulk data retrieval and normalization
- Aggregated results with success/failure tracking
- Export capabilities for data analysis
-
Smart Destination Decoding
- Handles 15+ AIS destination formats
- UN/LOCODE to readable port names
- Multi-format parsing (
BEZEE<>GBHUL,SGSIN=>BRPMA, etc.) - Fuzzy matching with 98% accuracy
- Country and port coordinate resolution
- COMPASS AI Assistant
- Context-aware conversations about vessels
- Maritime knowledge database
- Vessel specification queries
- Port information and routing advice
- Powered by Google Gemini AI
-
Redis Caching Layer
- 7-day TTL (Time To Live)
- 80-90% cache hit rate
- Sub-50ms response times for cached data
- Automatic cache invalidation
-
Efficient Data Processing
- Batch processing with rate limiting
- Parallel API calls
- Optimized database queries
- Lazy loading for improved UX
- Interactive Maps (Mapbox GL)
- Dark theme optimized for maritime data
- Custom vessel markers
- Destination port indicators
- Auto-fit bounds
- Zoom and navigation controls
- Popup information on hover
AIS (Automatic Identification System) destination data is notoriously inconsistent and difficult to interpret. Vessels report their destinations in various unpredictable formats:
β Raw AIS Data Problems:
"BEZEE <> GBHUL" β What does this mean?
"SGSIN=>BRPMA" β Which ports are these?
"LYBEN>>MTMAR" β Arrows? Really?
"TR IST" β UN/LOCODE format
"PORT SAID" β Full name (ambiguous)
"TBA" β To Be Announced (no info)
"GIBRALTAR EAST ANCH" β Port + Anchorage area
β
Our System Transforms:
"BEZEE <> GBHUL" β Zeebrugge, Belgium β Hull, United Kingdom
"SGSIN=>BRPMA" β Singapore β ParanaguΓ‘, Brazil
"LYBEN>>MTMAR" β Benghazi, Libya β Marsa, Malta
"TR IST" β Istanbul, Turkey (41.0082Β°N, 28.9784Β°E)
"PORT SAID" β Port Said, Egypt (31.2565Β°N, 32.2841Β°E)
How did I Do It:
- Pattern Recognition - 15+ format parsers for different AIS conventions
- UN/LOCODE Matching - Database of 100,000+ maritime locations
- Fuzzy Matching - 98% accuracy with intelligent similarity algorithms
- Route Extraction - Identifies final destination from multi-leg routes
- Geocoding - Provides precise coordinates for map visualization
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USER BROWSER β
β (React + Mapbox + Tailwind) β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββ
β
βββββββββ΄βββββββββ
β β
βΌ βΌ
ββββββββββββββββββ ββββββββββββββββββ
β Express.js β β Flask Backend β
β Backend API β β (AI-Model) β
ββββββββββββββββββ€ ββββββββββββββββββ€
β β’ Vessel Data β β β’ AIS Decoder β
β β’ Normalizationβ---->β β’ Gemini AI β
β β’ Map Data β β β’ Port Matcher β
β β’ Redis Cache β β β’ UN/LOCODE DB β
ββββββββββ¬ββββββββ ββββββββββ¬ββββββββ
β β
βΌ βΌ
ββββββββββββββββββ ββββββββββββββββββ
β Redis Cache β β locode.json β
β (7-day TTL) β β (Port Database)β
ββββββββββββββββββ ββββββββββββββββββ
β
βΌ
ββββββββββββββββββ
β AIS Friends β
β API Endpoint β
β (Discovered) β
ββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Request Flow β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. User Input (IMO: 9626390)
β
βββ Frontend React Component
β βββ API Service (axios)
β
2. Express Backend Receives Request
β
βββ Check Redis Cache
β βββ HIT: Return cached data (50ms)
β βββ MISS: Continue to API
β
3. Fetch from AIS Friends API
β βββ Raw vessel data retrieved
β
4. Data Normalization
β
βββ Normalize vessel name & type
β
βββ Send AIS destination to Flask
β β
β βββ Flask Port Matcher
β β βββ Pattern extraction
β β βββ UN/LOCODE matching
β β βββ Fuzzy matching
β β βββ Coordinate resolution
β β
β βββ Return: {port, country, lat, lon}
β
βββ Generate Mapbox markers
β
βββ Store in Redis (7-day TTL)
β
5. Return to Frontend
β
βββ Display: Map + Details + Table
User Initializes Chatbot
β
βββ Flask: Connects to Gemini API and initiates messaging
- React 18.3.1 - UI framework with hooks
- React Router 6 - Client-side routing
- Tailwind CSS v4 - Utility-first styling
- Mapbox GL JS - Interactive maps
- Axios - HTTP client
- Lucide React - Icon library
- Vite - Build tool & dev server
- Node.js 18+ - Runtime environment
- Express.js 4.18 - Web framework
- Redis 4.6 - Caching layer
- node-fetch 3.3 - HTTP requests
- dotenv - Environment management
- CORS - Cross-origin resource sharing
- Python 3.10+ - Runtime
- Flask 3.0 - Micro framework
- Flask-CORS - CORS handling
- Google Generative AI - Gemini integration
- Gunicorn - WSGI server
- Custom Port Matcher - UN/LOCODE algorithm
- Redis - In-memory data store
- Netlify - Frontend hosting
- Render - Backend hosting (Flask + Express)
- Mapbox - Map tiles and geocoding
- AIS Friends API - Vessel data source
- Google Gemini - AI chatbot
- Ollama Mistral - Local AI Model (testing prompt engineering)
- Jest - Testing framework
- ESLint - Code linting
- Git - Version control
- GitHub - Repository Storage
sequenceDiagram
participant User
participant Frontend
participant Express
participant Redis
participant AIS API
participant Flask
participant Gemini
User->>Frontend: Search IMO: 9626390
Frontend->>Express: GET /api/vessel/9626390
Express->>Redis: Check cache
alt Cache Hit
Redis-->>Express: Return cached data
Express-->>Frontend: Vessel data + map
else Cache Miss
Express->>AIS API: Fetch vessel data
AIS API-->>Express: Raw vessel data
Express->>Flask: POST /api/destination {dest: "TR IST"}
Flask->>Flask: UN/LOCODE matching
Flask-->>Express: {port: "Istanbul", country: "Turkey"}
Express->>Express: Generate map data
Express->>Redis: Store (7-day TTL)
Express-->>Frontend: Vessel data + map
end
Frontend->>User: Display map + details
User->>Frontend: Click chatbot
Frontend->>Flask: POST /api/chat/init
Flask->>Gemini: Initialize session
Gemini-->>Flask: Greeting message
Flask-->>Frontend: AI response
Frontend->>User: Show chat interface
User Input: [9626390, 9377418, 7349106]
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β Express: Check Redis for all IMOs β
βββββββββββββββββββββββββββββββββββββββ€
β Found in cache: [9626390] β β 1/3 cached
β Need to fetch: [9377418, 7349106] β β 2/3 fetch
βββββββββββββββββββ¬ββββββββββββββββββββ
β
βββββββββββ΄ββββββββββ
β β
βΌ βΌ
[Cached] [Fetch from API]
9626390 9377418, 7349106
β β
β ββββββ΄βββββ
β β β
β Normalize Normalize
β 9377418 7349106
β β β
β βββββ-βββββ
β βΌ βΌ
β Flask API Flask API
β β β
β βΌ βΌ
β Store Store
β Cache Cache
β β β
ββββββββββ-βββββββββ-βββββ
βΌ
ββββββββββββββββββββββββββββββ
β Combine all 3 vessels β
β Generate batch map data β
β Return to frontend β
ββββββββββββββββββββββββββββββ
Before you begin, ensure you have the following installed:
-
Node.js (v18.0.0 or higher)
node --version # Should be >= 18.0.0 -
npm (comes with Node.js)
npm --version
-
Python (v3.10 or higher)
python --version # Should be >= 3.10 -
Redis (v6.0 or higher)
redis-server --version
-
Git
git --version
git clone https://github.com/ryantusi/GMS_Vessel_Tracker.git
cd vessel-trackercd backend
# Install dependencies
npm install
# Create environment file
cp .env.example .env
# Edit .env with your credentials
# Required variables:
# - DESTINATION_DECODER_API (Flask URL)
# - MAPBOX_ACCESS_TOKEN (from Mapbox)
# - REDIS_URL (Redis connection string)Backend .env file:
# Flask API
DESTINATION_DECODER_API=http://127.0.0.1:10000/api/destination
AI_CHATBOT_API=http://127.0.0.1:10000/api/chat
# Server Configuration
PORT=5000
NODE_ENV=development
# Mapbox Configuration
MAPBOX_ACCESS_TOKEN=your_mapbox_token_here
MAPBOX_STYLE=mapbox://styles/your_style_here
# Redis Cache
REDIS_URL=redis://localhost:6379
# CORS
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173cd ../AI-Model
# Create virtual environment
python -m venv venv
# Activate virtual environment
# On Windows:
venv\Scripts\activate
# On Mac/Linux:
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Create environment file
cp .env.example .env
# Edit .env with your Gemini API keyFlask .env file:
PORT=10000
GEMINI_API_KEY=your_gemini_api_key_hereGet Gemini API Key:
- Go to https://makersuite.google.com/app/apikey
- Create new API key
- Copy and paste into
.env
cd ../frontend
# Install dependencies
npm install
# Create environment file
cp .env.example .env
# Edit .env with API URLsFrontend .env file:
# Backend API URL
VITE_API_URL=http://localhost:5000
# Mapbox Token
VITE_MAPBOX_TOKEN=your_mapbox_token_here
# Flask Backend
VITE_FLASK_API_URL=http://127.0.0.1:10000Get Mapbox Token:
- Go to https://account.mapbox.com/
- Create account (free)
- Copy your default public token
- Or create a new token with appropriate scopes
# On Windows (if installed via MSI):
redis-server
# On Mac (with Homebrew):
brew services start redis
# On Linux:
sudo systemctl start redis-server
# Or using Docker:
docker run -d --name redis -p 6379:6379 redis:latestVerify Redis is running:
redis-cli ping
# Should return: PONGOpen three separate terminal windows:
cd AI-Model
source venv/bin/activate # On Windows: venv\Scripts\activate
python app.pyExpected output:
β
Mock database loaded: 20 vessels
* Running on http://127.0.0.1:10000
cd backend
npm startExpected output:
β
Redis connected successfully
π’ Ship Tracker API running on port 5000
πΎ Redis cache: ENABLED
cd frontend
npm run devExpected output:
VITE v5.4.10 ready in 543 ms
β Local: http://localhost:5173/
β Network: use --host to expose
Open your browser and navigate to:
http://localhost:5173
You should see:
- β Disclaimer modal (explaining demo mode)
- β Home page with search forms
- β Interactive map centered on Suez Canal
- β No console errors
- Enter IMO:
9626390 - Click "Search Vessel"
- Should display vessel details and map
- Enter wrong IMO:
9711819 - Should display a clean error message
- Enter IMOs:
99626390, 9377418, 7349106, 9711819 (wrong imo) - Click "Search Multiple Vessels"
- Should display results table
- Click the floating chat button (bottom-right)
- Chat panel opens
- Type: "What is the status of vessel 9626390?"
- COMPASS responds with vessel information
vessel-tracker/
βββ AI-Model/ # Flask backend for AI & destination decoding
β βββ chatbot/ # Gemini AI chatbot implementation
β β βββ chatbot.py # Main chatbot logic
β β βββ testbot.py # Ollama test version
β βββ helper/ # Utility functions
β β βββ ais_port_matcher.py # UN/LOCODE matching algorithm
β β βββ script.py # Database generation script
β β βββ code-list.csv # UN/LOCODE port codes
β β βββ country-codes.csv # Country reference data
β β βββ locode.json # Generated port database (100K+ entries)
β βββ app.py # Flask application & routes
β βββ requirements.txt # Python dependencies
β βββ mock-vessels.json # Mock vessel database (deployment)
β βββ .env # Environment variables
β
βββ backend/ # Express.js backend API
β βββ utils/ # Utility modules
β β βββ apiData.js # AIS data fetching
β β βββ normalizer.js # Data normalization
β β βββ mapbox.js # Map data generation
β β βββ cache.js # Redis caching service
β βββ tests/ # Unit tests
β β βββ server.test.js # API endpoint tests
β β βββ setup.js # Test configuration
β βββ server.js # Express server & routes
β βββ package.json # Node dependencies
β βββ jest.config.js # Jest configuration
β βββ mock-vessels.json # Mock data (deployment)
β βββ .env # Environment variables
β
βββ frontend/ # React frontend application
β βββ src/
β β βββ components/ # React components
β β β βββ Chatbot.jsx # AI chatbot interface
β β β βββ DisclaimerModal.jsx # Demo disclaimer
β β β βββ ErrorMessage.jsx # Error handling
β β β βββ Footer.jsx # Page footer
β β β βββ LoadingSpinner.jsx # Loading states
β β β βββ MapComponent.jsx # Mapbox integration
β β βββ pages/ # Page components
β β β βββ Home.jsx # Landing page
β β β βββ SingleVessel.jsx # Vessel details
β β β βββ BatchVessels.jsx # Batch results
β β βββ services/ # API services
β β β βββ api.js # Axios API client
β β βββ App.jsx # Root component
β β βββ main.jsx # React entry point
β β βββ index.css # Global styles
β βββ public/ # Static assets
β βββ package.json # Node dependencies
β βββ vite.config.js # Vite configuration
β βββ tailwind.config.js # Tailwind CSS config
β βββ .env # Environment variables
β
βββ database/ # Mock database (deployment)
β βββ mock-vessels.json # 20 vessels for demo
β
βββ docs/ # Documentation
β βββ setup-guides/ # Setup instructions
β
βββ .gitignore # Git ignore rules
βββ LICENSE # MIT License
βββ README.md # This file
GET /Returns API information and available endpoints.
GET /api/vessel/:imoParameters:
imo- IMO number (7-10 digits)
Response:
{
"success": true,
"vessel": {
"imo": "9626390",
"name": "Ruby",
"type": "mv",
"ais_destination": {
"destination": "Istanbul, Turkey",
"port": "Istanbul",
"country": "Turkey",
"lat": 41.0082,
"lon": 28.9784
},
"latitude": 41.125858,
"longitude": 29.078135,
"navigational_status": "Underway using engine",
"speed_over_ground": 10.0,
"reportedDestination": "TR IST"
},
"map": {
"markers": [...],
"bounds": [[lng1, lat1], [lng2, lat2]],
"center": [lng, lat]
},
"cached": false
}POST /api/vessels/batch
Content-Type: application/json
{
"imos": ["9626390", "9377418", "7349106"]
}Response:
{
"success": true,
"totalRequested": 3,
"totalSuccess": 3,
"totalFailed": 0,
"cachedCount": 1,
"fetchedCount": 2,
"vessels": [...],
"map": {...}
}GET /api/cache/statsDELETE /api/cache/vessel/:imoGET /POST /api/destination
Content-Type: application/json
{
"destination": "TR IST"
}Response:
{
"reportedDestination": "TR IST",
"locode": "TRIST",
"port": "Istanbul",
"country": "Turkey",
"lat": 41.0082,
"lon": 28.9784,
"matched": true
}GET /api/chat/initPOST /api/chat
Content-Type: application/json
{
"message": "What is the status of vessel 9626390?"
}- Frontend: Netlify
- Express Backend: Render
- Flask Backend: Render
See detailed deployment guide: DEPLOYMENT.md
Summary:
- Deploy Flask β Get URL
- Deploy Express β Update with Flask URL
- Deploy Frontend β Update with both backend URLs
- Update CORS settings
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit changes (
git commit -m 'Add AmazingFeature') - Push to branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the CC0 1.0 Universal - see the LICENSE file for details.
- AIS Friends API - For providing accessible AIS vessel data (and for blocking my hosting priviledges everywhere)
- UN/LOCODE - Maritime location code system
- Mapbox - Interactive mapping platform
- Google Gemini - AI language model
- Ollama Mistral - AI Model for prompt engineering
- Open Source Community - For amazing tools and libraries
Ryan Tusi - LinkedIn
Portfolio: Click
AI-Model Flask | Express Backend | React Frontend
Built for the maritime industry. Engineered and Developed by Ryan Tusi, Full Stack + AI/ML Engineer
βοΈ π’ π