Spaces:
Sleeping
Sleeping
Upload 26 files
Browse files- .env.example +19 -0
- .env.snowflake +16 -0
- .gitattributes +35 -35
- .gitignore +89 -0
- DATA_INTEGRATION_GUIDE.md +92 -0
- DEPLOYMENT_GUIDE.md +185 -0
- Dockerfile +35 -0
- Dockerfile.fastapi +28 -0
- Dockerfile.streamlit +28 -0
- QUICK_DEPLOY.md +121 -0
- README.md +322 -12
- SNOWFLAKE_DEPLOYMENT.md +259 -0
- app.py +755 -755
- data_import.py +200 -0
- demo.py +304 -0
- demo_results.json +263 -0
- deploy.py +32 -0
- docker-compose.yml +63 -0
- game.js +385 -0
- index.html +45 -0
- main.py +220 -0
- netlify.toml +18 -0
- render.yaml +7 -0
- requirements.txt +24 -23
- styles.css +222 -0
- vercel.json +24 -0
.env.example
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Database Configuration (Server-side only)
|
| 2 |
+
DATABASE_URL=postgresql://username:password@localhost:5432/shipment_db
|
| 3 |
+
|
| 4 |
+
# API Keys (Server-side only - NOT exposed to client)
|
| 5 |
+
OPENWEATHER_API_KEY=your_openweather_api_key_here
|
| 6 |
+
GOOGLE_MAPS_API_KEY=your_google_maps_api_key_here
|
| 7 |
+
MAPBOX_ACCESS_TOKEN=your_mapbox_token_here
|
| 8 |
+
|
| 9 |
+
# Flask Configuration (Server-side only)
|
| 10 |
+
FLASK_ENV=production
|
| 11 |
+
SECRET_KEY=your_secret_key_here
|
| 12 |
+
|
| 13 |
+
# ML Model Configuration
|
| 14 |
+
MODEL_UPDATE_INTERVAL=24 # hours
|
| 15 |
+
PREDICTION_THRESHOLD=0.7
|
| 16 |
+
|
| 17 |
+
# Deployment Configuration
|
| 18 |
+
PORT=8050
|
| 19 |
+
HOST=0.0.0.0
|
.env.snowflake
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Snowflake Configuration for GreenPath
|
| 2 |
+
# Copy this to .env and fill in your Snowflake credentials
|
| 3 |
+
|
| 4 |
+
# Snowflake Account Details
|
| 5 |
+
SNOWFLAKE_ACCOUNT=your_account.region.cloud
|
| 6 |
+
SNOWFLAKE_USER=your_username
|
| 7 |
+
SNOWFLAKE_PASSWORD=your_password
|
| 8 |
+
SNOWFLAKE_DATABASE=GREENPATH
|
| 9 |
+
SNOWFLAKE_SCHEMA=EMISSIONS
|
| 10 |
+
SNOWFLAKE_WAREHOUSE=COMPUTE_WH
|
| 11 |
+
SNOWFLAKE_ROLE=ACCOUNTADMIN
|
| 12 |
+
|
| 13 |
+
# Application Settings
|
| 14 |
+
USE_SNOWFLAKE=true
|
| 15 |
+
CARBON_TAX_RATE=50.0
|
| 16 |
+
OPENROUTESERVICE_API_KEY=your_openroute_api_key
|
.gitattributes
CHANGED
|
@@ -1,35 +1,35 @@
|
|
| 1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AI-Powered Shipment Route Optimization System
|
| 2 |
+
# Created by: Zayeem Khateeb
|
| 3 |
+
|
| 4 |
+
# Environment variables
|
| 5 |
+
.env
|
| 6 |
+
.env.local
|
| 7 |
+
.env.production
|
| 8 |
+
|
| 9 |
+
# Python
|
| 10 |
+
__pycache__/
|
| 11 |
+
*.py[cod]
|
| 12 |
+
*$py.class
|
| 13 |
+
*.so
|
| 14 |
+
.Python
|
| 15 |
+
build/
|
| 16 |
+
develop-eggs/
|
| 17 |
+
dist/
|
| 18 |
+
downloads/
|
| 19 |
+
eggs/
|
| 20 |
+
.eggs/
|
| 21 |
+
lib/
|
| 22 |
+
lib64/
|
| 23 |
+
parts/
|
| 24 |
+
sdist/
|
| 25 |
+
var/
|
| 26 |
+
wheels/
|
| 27 |
+
*.egg-info/
|
| 28 |
+
.installed.cfg
|
| 29 |
+
*.egg
|
| 30 |
+
MANIFEST
|
| 31 |
+
|
| 32 |
+
# Virtual environments
|
| 33 |
+
venv/
|
| 34 |
+
env/
|
| 35 |
+
ENV/
|
| 36 |
+
env.bak/
|
| 37 |
+
venv.bak/
|
| 38 |
+
|
| 39 |
+
# IDE
|
| 40 |
+
.vscode/
|
| 41 |
+
.idea/
|
| 42 |
+
*.swp
|
| 43 |
+
*.swo
|
| 44 |
+
*~
|
| 45 |
+
|
| 46 |
+
# OS
|
| 47 |
+
.DS_Store
|
| 48 |
+
.DS_Store?
|
| 49 |
+
._*
|
| 50 |
+
.Spotlight-V100
|
| 51 |
+
.Trashes
|
| 52 |
+
ehthumbs.db
|
| 53 |
+
Thumbs.db
|
| 54 |
+
|
| 55 |
+
# Logs
|
| 56 |
+
*.log
|
| 57 |
+
logs/
|
| 58 |
+
|
| 59 |
+
# Database
|
| 60 |
+
*.db
|
| 61 |
+
*.sqlite
|
| 62 |
+
*.sqlite3
|
| 63 |
+
|
| 64 |
+
# ML Models
|
| 65 |
+
*.pkl
|
| 66 |
+
*.joblib
|
| 67 |
+
models/
|
| 68 |
+
|
| 69 |
+
# Data files (keep templates)
|
| 70 |
+
data/
|
| 71 |
+
!sample_data/
|
| 72 |
+
*.csv
|
| 73 |
+
!*template*.csv
|
| 74 |
+
|
| 75 |
+
# Temporary files
|
| 76 |
+
temp/
|
| 77 |
+
tmp/
|
| 78 |
+
*.tmp
|
| 79 |
+
|
| 80 |
+
# Docker
|
| 81 |
+
.dockerignore
|
| 82 |
+
|
| 83 |
+
# Deployment
|
| 84 |
+
.vercel
|
| 85 |
+
.netlify
|
| 86 |
+
|
| 87 |
+
# Cache
|
| 88 |
+
.cache/
|
| 89 |
+
*.cache
|
DATA_INTEGRATION_GUIDE.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Data Integration Guide
|
| 2 |
+
## How to Add Your Real Data to the AI-Powered Shipment Route Optimization System
|
| 3 |
+
|
| 4 |
+
**Created by: Zayeem Khateeb**
|
| 5 |
+
|
| 6 |
+
## 🗄️ **Method 1: Database Integration (Recommended)**
|
| 7 |
+
|
| 8 |
+
### Step 1: Set up your database
|
| 9 |
+
1. Copy `.env.example` to `.env`
|
| 10 |
+
2. Update database connection:
|
| 11 |
+
```
|
| 12 |
+
DATABASE_URL=postgresql://your_username:your_password@localhost:5432/your_database
|
| 13 |
+
```
|
| 14 |
+
|
| 15 |
+
### Step 2: Create tables using the provided schema
|
| 16 |
+
Run this in your PostgreSQL database:
|
| 17 |
+
|
| 18 |
+
```sql
|
| 19 |
+
-- Shipments table
|
| 20 |
+
CREATE TABLE shipments (
|
| 21 |
+
id SERIAL PRIMARY KEY,
|
| 22 |
+
tracking_number VARCHAR(50) UNIQUE NOT NULL,
|
| 23 |
+
origin_lat DECIMAL(10, 8),
|
| 24 |
+
origin_lng DECIMAL(11, 8),
|
| 25 |
+
destination_lat DECIMAL(10, 8),
|
| 26 |
+
destination_lng DECIMAL(11, 8),
|
| 27 |
+
origin_address TEXT,
|
| 28 |
+
destination_address TEXT,
|
| 29 |
+
scheduled_delivery TIMESTAMP,
|
| 30 |
+
actual_delivery TIMESTAMP,
|
| 31 |
+
status VARCHAR(20) DEFAULT 'pending',
|
| 32 |
+
delay_minutes INTEGER DEFAULT 0,
|
| 33 |
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
| 34 |
+
);
|
| 35 |
+
|
| 36 |
+
-- Weather data table
|
| 37 |
+
CREATE TABLE weather_data (
|
| 38 |
+
id SERIAL PRIMARY KEY,
|
| 39 |
+
location_lat DECIMAL(10, 8),
|
| 40 |
+
location_lng DECIMAL(11, 8),
|
| 41 |
+
timestamp TIMESTAMP,
|
| 42 |
+
temperature DECIMAL(5, 2),
|
| 43 |
+
humidity INTEGER,
|
| 44 |
+
wind_speed DECIMAL(5, 2),
|
| 45 |
+
precipitation DECIMAL(5, 2),
|
| 46 |
+
weather_condition VARCHAR(50)
|
| 47 |
+
);
|
| 48 |
+
|
| 49 |
+
-- Traffic data table
|
| 50 |
+
CREATE TABLE traffic_data (
|
| 51 |
+
id SERIAL PRIMARY KEY,
|
| 52 |
+
route_start_lat DECIMAL(10, 8),
|
| 53 |
+
route_start_lng DECIMAL(11, 8),
|
| 54 |
+
route_end_lat DECIMAL(10, 8),
|
| 55 |
+
route_end_lng DECIMAL(11, 8),
|
| 56 |
+
timestamp TIMESTAMP,
|
| 57 |
+
travel_time_minutes INTEGER,
|
| 58 |
+
distance_km DECIMAL(8, 2),
|
| 59 |
+
traffic_level VARCHAR(20)
|
| 60 |
+
);
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
### Step 3: Insert your shipment data
|
| 64 |
+
```sql
|
| 65 |
+
INSERT INTO shipments (
|
| 66 |
+
tracking_number, origin_lat, origin_lng, destination_lat, destination_lng,
|
| 67 |
+
origin_address, destination_address, scheduled_delivery, status
|
| 68 |
+
) VALUES (
|
| 69 |
+
'YOUR_TRACKING_001', 40.7128, -74.0060, 34.0522, -118.2437,
|
| 70 |
+
'New York, NY', 'Los Angeles, CA', '2025-01-15 14:00:00', 'in_transit'
|
| 71 |
+
);
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
## 📁 **Method 2: CSV File Import**
|
| 75 |
+
|
| 76 |
+
### Step 1: Prepare your CSV files
|
| 77 |
+
|
| 78 |
+
#### shipments.csv
|
| 79 |
+
```csv
|
| 80 |
+
tracking_number,origin_lat,origin_lng,destination_lat,destination_lng,origin_address,destination_address,scheduled_delivery,actual_delivery,status,delay_minutes
|
| 81 |
+
TRK001,40.7128,-74.0060,34.0522,-118.2437,"New York NY","Los Angeles CA",2025-01-15 14:00:00,2025-01-15 16:30:00,delivered,150
|
| 82 |
+
TRK002,41.8781,-87.6298,29.7604,-95.3698,"Chicago IL","Houston TX",2025-01-16 10:00:00,,in_transit,0
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
#### weather_data.csv
|
| 86 |
+
```csv
|
| 87 |
+
location_lat,location_lng,timestamp,temperature,humidity,wind_speed,precipitation,weather_condition
|
| 88 |
+
40.7128,-74.0060,2025-01-15 12:00:00,15.5,65,12.3,0.0,Clear
|
| 89 |
+
34.0522,-118.2437,2025-01-15 12:00:00,22.1,45,8.7,0.0,Sunny
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
### Step 2: Create a data import script
|
DEPLOYMENT_GUIDE.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚀 Deployment Guide
|
| 2 |
+
## AI-Powered Shipment Route Optimization System
|
| 3 |
+
**Created by: Zayeem Khateeb**
|
| 4 |
+
|
| 5 |
+
## 📋 Deployment Options
|
| 6 |
+
|
| 7 |
+
### Option 1: Docker Deployment (Recommended)
|
| 8 |
+
|
| 9 |
+
#### Prerequisites
|
| 10 |
+
- Docker and Docker Compose installed
|
| 11 |
+
- 4GB RAM minimum
|
| 12 |
+
- 10GB disk space
|
| 13 |
+
|
| 14 |
+
#### Steps
|
| 15 |
+
```bash
|
| 16 |
+
# 1. Build and run with Docker Compose
|
| 17 |
+
docker-compose up -d
|
| 18 |
+
|
| 19 |
+
# 2. Access your application
|
| 20 |
+
http://localhost:8050
|
| 21 |
+
|
| 22 |
+
# 3. View logs
|
| 23 |
+
docker-compose logs -f dashboard
|
| 24 |
+
|
| 25 |
+
# 4. Stop deployment
|
| 26 |
+
docker-compose down
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
### Option 2: Cloud Deployment (Heroku)
|
| 30 |
+
|
| 31 |
+
#### Prerequisites
|
| 32 |
+
- Heroku CLI installed
|
| 33 |
+
- Git repository
|
| 34 |
+
|
| 35 |
+
#### Steps
|
| 36 |
+
```bash
|
| 37 |
+
# 1. Login to Heroku
|
| 38 |
+
heroku login
|
| 39 |
+
|
| 40 |
+
# 2. Create Heroku app
|
| 41 |
+
heroku create your-shipment-optimizer
|
| 42 |
+
|
| 43 |
+
# 3. Set environment variables
|
| 44 |
+
heroku config:set FLASK_ENV=production
|
| 45 |
+
heroku config:set SECRET_KEY=your-secret-key
|
| 46 |
+
|
| 47 |
+
# 4. Deploy
|
| 48 |
+
git add .
|
| 49 |
+
git commit -m "Deploy AI Shipment Optimizer"
|
| 50 |
+
git push heroku main
|
| 51 |
+
|
| 52 |
+
# 5. Open your app
|
| 53 |
+
heroku open
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
### Option 3: Vercel Deployment
|
| 57 |
+
|
| 58 |
+
#### Prerequisites
|
| 59 |
+
- Vercel CLI or GitHub integration
|
| 60 |
+
|
| 61 |
+
#### Steps
|
| 62 |
+
```bash
|
| 63 |
+
# 1. Install Vercel CLI
|
| 64 |
+
npm i -g vercel
|
| 65 |
+
|
| 66 |
+
# 2. Deploy
|
| 67 |
+
vercel
|
| 68 |
+
|
| 69 |
+
# 3. Follow prompts and get your URL
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
### Option 4: Railway Deployment
|
| 73 |
+
|
| 74 |
+
#### Steps
|
| 75 |
+
```bash
|
| 76 |
+
# 1. Install Railway CLI
|
| 77 |
+
npm install -g @railway/cli
|
| 78 |
+
|
| 79 |
+
# 2. Login
|
| 80 |
+
railway login
|
| 81 |
+
|
| 82 |
+
# 3. Deploy
|
| 83 |
+
railway up
|
| 84 |
+
|
| 85 |
+
# 4. Get your URL
|
| 86 |
+
railway domain
|
| 87 |
+
```
|
| 88 |
+
|
| 89 |
+
### Option 5: Local Production Server
|
| 90 |
+
|
| 91 |
+
#### Steps
|
| 92 |
+
```bash
|
| 93 |
+
# 1. Install production server
|
| 94 |
+
pip install gunicorn
|
| 95 |
+
|
| 96 |
+
# 2. Run production server
|
| 97 |
+
gunicorn -w 4 -b 0.0.0.0:8050 deploy:app
|
| 98 |
+
|
| 99 |
+
# 3. Access at http://localhost:8050
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
## 🔧 Environment Variables
|
| 103 |
+
|
| 104 |
+
Create `.env` file with:
|
| 105 |
+
```
|
| 106 |
+
# Database
|
| 107 |
+
DATABASE_URL=your_database_url
|
| 108 |
+
|
| 109 |
+
# API Keys
|
| 110 |
+
OPENWEATHER_API_KEY=your_weather_api_key
|
| 111 |
+
GOOGLE_MAPS_API_KEY=your_maps_api_key
|
| 112 |
+
|
| 113 |
+
# Security
|
| 114 |
+
SECRET_KEY=your-secret-key-here
|
| 115 |
+
|
| 116 |
+
# App Config
|
| 117 |
+
FLASK_ENV=production
|
| 118 |
+
PORT=8050
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
## 📊 Performance Optimization
|
| 122 |
+
|
| 123 |
+
### For Production:
|
| 124 |
+
1. **Enable caching**: Redis configured in docker-compose
|
| 125 |
+
2. **Database optimization**: PostgreSQL with proper indexing
|
| 126 |
+
3. **Load balancing**: Multiple worker processes
|
| 127 |
+
4. **Monitoring**: Built-in health checks
|
| 128 |
+
|
| 129 |
+
### Scaling:
|
| 130 |
+
- **Horizontal**: Multiple container instances
|
| 131 |
+
- **Vertical**: Increase CPU/RAM allocation
|
| 132 |
+
- **Database**: Separate database server
|
| 133 |
+
|
| 134 |
+
## 🔒 Security Checklist
|
| 135 |
+
|
| 136 |
+
- ✅ Environment variables for secrets
|
| 137 |
+
- ✅ Non-root Docker user
|
| 138 |
+
- ✅ HTTPS in production (handled by platform)
|
| 139 |
+
- ✅ Input validation and sanitization
|
| 140 |
+
- ✅ Database connection security
|
| 141 |
+
|
| 142 |
+
## 📈 Monitoring
|
| 143 |
+
|
| 144 |
+
### Health Check Endpoint:
|
| 145 |
+
```
|
| 146 |
+
GET /health
|
| 147 |
+
```
|
| 148 |
+
|
| 149 |
+
### Metrics Available:
|
| 150 |
+
- Total shipments processed
|
| 151 |
+
- ML model accuracy
|
| 152 |
+
- Response times
|
| 153 |
+
- Error rates
|
| 154 |
+
|
| 155 |
+
## 🆘 Troubleshooting
|
| 156 |
+
|
| 157 |
+
### Common Issues:
|
| 158 |
+
|
| 159 |
+
1. **Port already in use**
|
| 160 |
+
```bash
|
| 161 |
+
# Change port in docker-compose.yml or .env
|
| 162 |
+
PORT=8051
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
2. **Database connection failed**
|
| 166 |
+
```bash
|
| 167 |
+
# Check DATABASE_URL in .env
|
| 168 |
+
# Ensure database is running
|
| 169 |
+
```
|
| 170 |
+
|
| 171 |
+
3. **ML model training fails**
|
| 172 |
+
```bash
|
| 173 |
+
# Check data format
|
| 174 |
+
# Increase memory allocation
|
| 175 |
+
```
|
| 176 |
+
|
| 177 |
+
## 📞 Support
|
| 178 |
+
|
| 179 |
+
For deployment issues:
|
| 180 |
+
1. Check logs: `docker-compose logs dashboard`
|
| 181 |
+
2. Verify environment variables
|
| 182 |
+
3. Ensure all dependencies are installed
|
| 183 |
+
4. Check system requirements
|
| 184 |
+
|
| 185 |
+
Your AI-Powered Shipment Route Optimization System is ready for production! 🎉
|
Dockerfile
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AI-Powered Shipment Route Optimization System
|
| 2 |
+
# Created by: Zayeem Khateeb
|
| 3 |
+
FROM python:3.11-slim
|
| 4 |
+
|
| 5 |
+
# Set working directory
|
| 6 |
+
WORKDIR /app
|
| 7 |
+
|
| 8 |
+
# Install system dependencies
|
| 9 |
+
RUN apt-get update && apt-get install -y \
|
| 10 |
+
gcc \
|
| 11 |
+
g++ \
|
| 12 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 13 |
+
|
| 14 |
+
# Copy requirements first for better caching
|
| 15 |
+
COPY requirements.txt .
|
| 16 |
+
|
| 17 |
+
# Install Python dependencies
|
| 18 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 19 |
+
|
| 20 |
+
# Copy application code
|
| 21 |
+
COPY . .
|
| 22 |
+
|
| 23 |
+
# Create non-root user for security
|
| 24 |
+
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
|
| 25 |
+
USER appuser
|
| 26 |
+
|
| 27 |
+
# Expose port
|
| 28 |
+
EXPOSE 8050
|
| 29 |
+
|
| 30 |
+
# Health check
|
| 31 |
+
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
|
| 32 |
+
CMD curl -f http://localhost:8050/ || exit 1
|
| 33 |
+
|
| 34 |
+
# Run the application
|
| 35 |
+
CMD ["python", "src/dashboard/app.py"]
|
Dockerfile.fastapi
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.9-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
# Install system dependencies
|
| 6 |
+
RUN apt-get update && apt-get install -y \
|
| 7 |
+
gcc \
|
| 8 |
+
g++ \
|
| 9 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
+
|
| 11 |
+
# Copy requirements and install Python dependencies
|
| 12 |
+
COPY requirements.txt .
|
| 13 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 14 |
+
|
| 15 |
+
# Copy application code
|
| 16 |
+
COPY . .
|
| 17 |
+
|
| 18 |
+
# Create data directory
|
| 19 |
+
RUN mkdir -p /app/data
|
| 20 |
+
|
| 21 |
+
# Expose FastAPI port
|
| 22 |
+
EXPOSE 8000
|
| 23 |
+
|
| 24 |
+
# Health check
|
| 25 |
+
HEALTHCHECK CMD curl --fail http://localhost:8000/health
|
| 26 |
+
|
| 27 |
+
# Run FastAPI app
|
| 28 |
+
CMD ["python", "src/api/main.py"]
|
Dockerfile.streamlit
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.9-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
# Install system dependencies
|
| 6 |
+
RUN apt-get update && apt-get install -y \
|
| 7 |
+
gcc \
|
| 8 |
+
g++ \
|
| 9 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
+
|
| 11 |
+
# Copy requirements and install Python dependencies
|
| 12 |
+
COPY requirements.txt .
|
| 13 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 14 |
+
|
| 15 |
+
# Copy application code
|
| 16 |
+
COPY . .
|
| 17 |
+
|
| 18 |
+
# Create data directory
|
| 19 |
+
RUN mkdir -p /app/data
|
| 20 |
+
|
| 21 |
+
# Expose Streamlit port
|
| 22 |
+
EXPOSE 8501
|
| 23 |
+
|
| 24 |
+
# Health check
|
| 25 |
+
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
|
| 26 |
+
|
| 27 |
+
# Run Streamlit app
|
| 28 |
+
CMD ["streamlit", "run", "streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
|
QUICK_DEPLOY.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚀 Quick Deployment Instructions
|
| 2 |
+
## AI-Powered Shipment Route Optimization System
|
| 3 |
+
**Created by: Zayeem Khateeb**
|
| 4 |
+
|
| 5 |
+
## ⚡ Instant Deploy Options
|
| 6 |
+
|
| 7 |
+
### Option 1: Heroku (Recommended - Free Tier Available)
|
| 8 |
+
```bash
|
| 9 |
+
# 1. Install Heroku CLI from: https://devcenter.heroku.com/articles/heroku-cli
|
| 10 |
+
# 2. Login and create app
|
| 11 |
+
heroku login
|
| 12 |
+
heroku create ai-shipment-optimizer-[your-name]
|
| 13 |
+
|
| 14 |
+
# 3. Set environment variables
|
| 15 |
+
heroku config:set FLASK_ENV=production
|
| 16 |
+
|
| 17 |
+
## 🌨️ Step 1: Set Up Snowflake
|
| 18 |
+
|
| 19 |
+
### 1.1 Create Snowflake Account
|
| 20 |
+
```sql
|
| 21 |
+
-- After signing up, run these commands in Snowflake worksheet:
|
| 22 |
+
|
| 23 |
+
-- Create database and schema
|
| 24 |
+
CREATE DATABASE GREENPATH;
|
| 25 |
+
CREATE SCHEMA GREENPATH.EMISSIONS;
|
| 26 |
+
|
| 27 |
+
-- Create warehouse
|
| 28 |
+
CREATE WAREHOUSE COMPUTE_WH WITH
|
| 29 |
+
WAREHOUSE_SIZE = 'X-SMALL'
|
| 30 |
+
AUTO_SUSPEND = 60
|
| 31 |
+
AUTO_RESUME = TRUE;
|
| 32 |
+
|
| 33 |
+
-- Grant permissions
|
| 34 |
+
GRANT USAGE ON DATABASE GREENPATH TO ROLE ACCOUNTADMIN;
|
| 35 |
+
GRANT USAGE ON SCHEMA GREENPATH.EMISSIONS TO ROLE ACCOUNTADMIN;
|
| 36 |
+
GRANT USAGE ON WAREHOUSE COMPUTE_WH TO ROLE ACCOUNTADMIN;
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
### 1.2 Get Snowflake Connection Details
|
| 40 |
+
- **Account**: `your_account.region.cloud` (from Snowflake URL)
|
| 41 |
+
- **Username**: Your Snowflake username
|
| 42 |
+
- **Password**: Your Snowflake password
|
| 43 |
+
|
| 44 |
+
## 🌐 Step 2: Deploy to Streamlit Cloud
|
| 45 |
+
|
| 46 |
+
### 2.1 Push Latest Code to GitHub
|
| 47 |
+
```bash
|
| 48 |
+
# Commit Snowflake integration
|
| 49 |
+
git add .
|
| 50 |
+
git commit -m "Add Snowflake integration for enterprise deployment"
|
| 51 |
+
git push origin main
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
### 2.2 Deploy on Streamlit Cloud
|
| 55 |
+
1. Go to [share.streamlit.io](https://share.streamlit.io)
|
| 56 |
+
2. Click **"New app"**
|
| 57 |
+
3. Connect your GitHub account
|
| 58 |
+
4. Select repository: `zayeemskhateeb-cloud/greenpath-ai-emission-tracker`
|
| 59 |
+
5. Main file path: `streamlit_app.py`
|
| 60 |
+
6. Advanced settings → Python version: `3.9`
|
| 61 |
+
7. Click **"Deploy!"**
|
| 62 |
+
|
| 63 |
+
### 2.3 Configure Secrets
|
| 64 |
+
In Streamlit Cloud dashboard → App settings → Secrets:
|
| 65 |
+
|
| 66 |
+
```toml
|
| 67 |
+
[snowflake]
|
| 68 |
+
account = "your_account.region.cloud"
|
| 69 |
+
user = "your_username"
|
| 70 |
+
password = "your_password"
|
| 71 |
+
database = "GREENPATH"
|
| 72 |
+
schema = "EMISSIONS"
|
| 73 |
+
warehouse = "COMPUTE_WH"
|
| 74 |
+
role = "ACCOUNTADMIN"
|
| 75 |
+
|
| 76 |
+
[openroute]
|
| 77 |
+
api_key = "your_openroute_api_key" # Optional
|
| 78 |
+
|
| 79 |
+
[app]
|
| 80 |
+
carbon_tax_rate = "50.0"
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
## 🎯 Step 3: Verify Deployment
|
| 84 |
+
|
| 85 |
+
### 3.1 Your Live Application
|
| 86 |
+
- **URL**: `https://your-app-name.streamlit.app`
|
| 87 |
+
- **Features**: All GreenPath functionality with Snowflake backend
|
| 88 |
+
|
| 89 |
+
### 3.2 Test Checklist
|
| 90 |
+
- ✅ Dashboard loads with emission metrics
|
| 91 |
+
- ✅ CO₂ Calculator works with all transport modes
|
| 92 |
+
- ✅ Route Optimizer provides recommendations
|
| 93 |
+
- ✅ Business Impact Simulation runs scenarios
|
| 94 |
+
- ✅ Analytics display interactive charts
|
| 95 |
+
- ✅ Data persists in Snowflake (if configured)
|
| 96 |
+
|
| 97 |
+
## 🔧 Optional Enhancements
|
| 98 |
+
|
| 99 |
+
### Enable Snowflake Data Persistence
|
| 100 |
+
Update `streamlit_app.py` to use Snowflake models:
|
| 101 |
+
|
| 102 |
+
```python
|
| 103 |
+
# Add at top of streamlit_app.py
|
| 104 |
+
import os
|
| 105 |
+
if os.getenv('USE_SNOWFLAKE', 'false').lower() == 'true':
|
| 106 |
+
from src.database.snowflake_models import SnowflakeDataManager
|
| 107 |
+
data_manager = SnowflakeDataManager()
|
| 108 |
+
```
|
| 109 |
+
|
| 110 |
+
### Custom Domain (Optional)
|
| 111 |
+
- Upgrade to Streamlit Cloud Pro for custom domain
|
| 112 |
+
- Configure DNS to point to your Streamlit app
|
| 113 |
+
|
| 114 |
+
1. **Python not found**: Install Python 3.11+ from python.org
|
| 115 |
+
2. **Dependencies fail**: Use `pip install --upgrade pip` first
|
| 116 |
+
3. **Port in use**: Change PORT in environment variables
|
| 117 |
+
4. **Database issues**: System works with SQLite by default
|
| 118 |
+
|
| 119 |
+
Your AI-Powered Shipment Route Optimization System is ready to deploy! 🎉
|
| 120 |
+
|
| 121 |
+
**Created with ❤️ by Zayeem Khateeb**
|
README.md
CHANGED
|
@@ -1,12 +1,322 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🌱 GreenPath: AI & Data Analytics Platform for Reducing Shipment CO₂ Emissions
|
| 2 |
+
|
| 3 |
+
**Designed and Developed by Sayed Mohd Zayeem Khateeb**
|
| 4 |
+
|
| 5 |
+
[](https://opensource.org/licenses/MIT)
|
| 6 |
+
[](https://www.python.org/downloads/)
|
| 7 |
+
[](https://streamlit.io/)
|
| 8 |
+
[](https://fastapi.tiangolo.com/)
|
| 9 |
+
|
| 10 |
+
## 🎯 Overview
|
| 11 |
+
|
| 12 |
+
GreenPath is an **AI-powered platform** that helps logistics and supply chain companies **measure, analyze, and reduce CO₂ emissions per shipment** while recommending **optimized delivery routes** that minimize emissions without significantly affecting delivery time or cost.
|
| 13 |
+
|
| 14 |
+
### 🏆 Key Achievements
|
| 15 |
+
- **22% reduction in CO₂ emissions** through green route optimization
|
| 16 |
+
- **Real-time emission tracking** with IPCC-compliant calculations
|
| 17 |
+
- **Multi-objective optimization** balancing emissions, cost, and delivery time
|
| 18 |
+
- **Professional dashboard** with eco-friendly design and advanced analytics
|
| 19 |
+
|
| 20 |
+
## 🌟 Core Features
|
| 21 |
+
|
| 22 |
+
### 1. 🧮 CO₂ Emission Calculator
|
| 23 |
+
- **Formula-based estimation**: `CO₂ = Distance × Weight × EmissionFactor`
|
| 24 |
+
- **Multiple transport modes**: Road, Rail, Air, Ship (Container & Bulk)
|
| 25 |
+
- **IPCC 2019 Guidelines compliance** for emission factors
|
| 26 |
+
- **Carbon tax cost calculation** with customizable rates
|
| 27 |
+
|
| 28 |
+
### 2. 🗺️ Green Route Recommendation Engine
|
| 29 |
+
- **OpenRouteService API integration** for accurate routing
|
| 30 |
+
- **Multi-modal transport optimization** (truck + rail combinations)
|
| 31 |
+
- **Time constraint balancing** (max 10% time penalty for green options)
|
| 32 |
+
- **Emission reduction visualization** with percentage improvements
|
| 33 |
+
|
| 34 |
+
### 3. 📊 Analytics Dashboard
|
| 35 |
+
- **Professional eco-friendly design** (green accents, clean layout)
|
| 36 |
+
- **Real-time KPIs**: Total emissions, reduction percentage, carbon tax savings
|
| 37 |
+
- **Interactive visualizations**: Transport mode comparison, emission trends
|
| 38 |
+
- **Regional analysis** and performance metrics
|
| 39 |
+
|
| 40 |
+
### 4. 📈 Business Impact Simulation
|
| 41 |
+
- **Scenario analysis**: "What if X% shipments use optimized routes?"
|
| 42 |
+
- **Financial impact**: Carbon tax savings and ESG score improvement
|
| 43 |
+
- **ROI calculations** for sustainability investments
|
| 44 |
+
- **Regulatory compliance** readiness assessment
|
| 45 |
+
|
| 46 |
+
### 5. 📋 Comprehensive Reporting
|
| 47 |
+
- **PDF reports** with executive summaries and recommendations
|
| 48 |
+
- **Excel exports** with detailed shipment data and analytics
|
| 49 |
+
- **Downloadable formats** for management review and compliance
|
| 50 |
+
|
| 51 |
+
## 🚀 Quick Start
|
| 52 |
+
|
| 53 |
+
### Option 1: Streamlit Web App (Recommended)
|
| 54 |
+
```bash
|
| 55 |
+
# Clone the repository
|
| 56 |
+
git clone https://github.com/zayeemskhateeb-cloud/greenpath-ai-emission-tracker.git
|
| 57 |
+
cd greenpath-ai-emission-tracker
|
| 58 |
+
|
| 59 |
+
# Install dependencies
|
| 60 |
+
pip install -r requirements.txt
|
| 61 |
+
|
| 62 |
+
# Run the Streamlit app
|
| 63 |
+
streamlit run streamlit_app.py
|
| 64 |
+
|
| 65 |
+
# Access at http://localhost:8501
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
### Option 2: FastAPI Backend + Frontend
|
| 69 |
+
```bash
|
| 70 |
+
# Terminal 1: Start FastAPI backend
|
| 71 |
+
cd src/api
|
| 72 |
+
python main.py
|
| 73 |
+
# Backend available at http://localhost:8000
|
| 74 |
+
|
| 75 |
+
# Terminal 2: Start Streamlit frontend
|
| 76 |
+
streamlit run streamlit_app.py
|
| 77 |
+
# Frontend available at http://localhost:8501
|
| 78 |
+
```
|
| 79 |
+
|
| 80 |
+
### Option 3: Docker Deployment
|
| 81 |
+
```bash
|
| 82 |
+
# Build and run with Docker Compose
|
| 83 |
+
docker-compose up -d
|
| 84 |
+
|
| 85 |
+
# Access services:
|
| 86 |
+
# - Streamlit: http://localhost:8501
|
| 87 |
+
# - FastAPI: http://localhost:8000
|
| 88 |
+
# - API Docs: http://localhost:8000/docs
|
| 89 |
+
```
|
| 90 |
+
|
| 91 |
+
## 🛠️ Technology Stack
|
| 92 |
+
|
| 93 |
+
### Backend & AI
|
| 94 |
+
- **Python 3.8+** - Core programming language
|
| 95 |
+
- **FastAPI** - High-performance API framework
|
| 96 |
+
- **SQLAlchemy** - Database ORM with SQLite
|
| 97 |
+
- **Pandas & NumPy** - Data processing and analytics
|
| 98 |
+
- **Scikit-learn** - Machine learning capabilities
|
| 99 |
+
|
| 100 |
+
### Frontend & Visualization
|
| 101 |
+
- **Streamlit** - Interactive web application framework
|
| 102 |
+
- **Plotly** - Advanced data visualizations
|
| 103 |
+
- **Folium** - Interactive maps for route visualization
|
| 104 |
+
- **Custom CSS** - Professional eco-friendly design
|
| 105 |
+
|
| 106 |
+
### APIs & Integration
|
| 107 |
+
- **OpenRouteService** - Route optimization and geocoding
|
| 108 |
+
- **IPCC Emission Factors** - Scientifically accurate CO₂ calculations
|
| 109 |
+
- **RESTful APIs** - Seamless integration capabilities
|
| 110 |
+
|
| 111 |
+
### Reports & Export
|
| 112 |
+
- **ReportLab** - Professional PDF report generation
|
| 113 |
+
- **OpenPyXL** - Excel export functionality
|
| 114 |
+
- **Custom templates** - Branded report formats
|
| 115 |
+
|
| 116 |
+
## 📁 Project Structure
|
| 117 |
+
|
| 118 |
+
```
|
| 119 |
+
greenpath-ai-emission-tracker/
|
| 120 |
+
├── src/
|
| 121 |
+
│ ├── api/ # FastAPI backend
|
| 122 |
+
│ │ └── main.py # API endpoints and logic
|
| 123 |
+
│ ├── emissions/ # CO₂ calculation engine
|
| 124 |
+
│ │ └── emission_calculator.py
|
| 125 |
+
│ ├── route_optimizer/ # Green route optimization
|
| 126 |
+
│ │ └── green_route_optimizer.py
|
| 127 |
+
│ ├── database/ # Data models and storage
|
| 128 |
+
│ │ └── models.py
|
| 129 |
+
│ └── reports/ # Report generation
|
| 130 |
+
│ └── report_generator.py
|
| 131 |
+
├── streamlit_app.py # Main Streamlit application
|
| 132 |
+
├── requirements.txt # Python dependencies
|
| 133 |
+
├── docker-compose.yml # Container orchestration
|
| 134 |
+
├── .env.example # Environment variables template
|
| 135 |
+
└── README.md # This file
|
| 136 |
+
```
|
| 137 |
+
|
| 138 |
+
## 🔧 Configuration
|
| 139 |
+
|
| 140 |
+
### 1. Environment Setup
|
| 141 |
+
```bash
|
| 142 |
+
# Copy environment template
|
| 143 |
+
cp .env.example .env
|
| 144 |
+
|
| 145 |
+
# Add your API keys (optional for basic functionality)
|
| 146 |
+
OPENROUTESERVICE_API_KEY=your_key_here
|
| 147 |
+
DATABASE_URL=sqlite:///greenpath.db
|
| 148 |
+
```
|
| 149 |
+
|
| 150 |
+
### 2. API Keys (Optional)
|
| 151 |
+
- **OpenRouteService**: For enhanced routing (free tier available)
|
| 152 |
+
- **No API keys required** for basic emission calculations and demo functionality
|
| 153 |
+
|
| 154 |
+
### 3. Database
|
| 155 |
+
- **SQLite** (default): Automatic setup, no configuration needed
|
| 156 |
+
- **PostgreSQL**: Update DATABASE_URL in .env for production
|
| 157 |
+
|
| 158 |
+
## 📊 Usage Examples
|
| 159 |
+
|
| 160 |
+
### Emission Calculator
|
| 161 |
+
```python
|
| 162 |
+
from src.emissions.emission_calculator import EmissionCalculator, TransportMode
|
| 163 |
+
|
| 164 |
+
calculator = EmissionCalculator()
|
| 165 |
+
|
| 166 |
+
# Calculate emissions for a truck shipment
|
| 167 |
+
result = calculator.calculate_emissions(
|
| 168 |
+
distance_km=500,
|
| 169 |
+
weight_tonnes=2.5,
|
| 170 |
+
transport_mode=TransportMode.ROAD_TRUCK
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
print(f"CO₂ Emissions: {result['co2_emissions_kg']} kg")
|
| 174 |
+
# Output: CO₂ Emissions: 77.5 kg
|
| 175 |
+
```
|
| 176 |
+
|
| 177 |
+
### Route Optimization
|
| 178 |
+
```python
|
| 179 |
+
from src.route_optimizer.green_route_optimizer import GreenRouteOptimizer
|
| 180 |
+
|
| 181 |
+
optimizer = GreenRouteOptimizer()
|
| 182 |
+
|
| 183 |
+
# Get green route recommendations
|
| 184 |
+
recommendations = optimizer.recommend_green_routes(
|
| 185 |
+
origin="New York, NY",
|
| 186 |
+
destination="Los Angeles, CA",
|
| 187 |
+
weight_tonnes=5.0
|
| 188 |
+
)
|
| 189 |
+
|
| 190 |
+
print(f"Greenest option: {recommendations['summary']['greenest_option']}")
|
| 191 |
+
```
|
| 192 |
+
|
| 193 |
+
## 📈 Business Impact
|
| 194 |
+
|
| 195 |
+
### Environmental Benefits
|
| 196 |
+
- **Up to 22% reduction** in CO₂ emissions per shipment
|
| 197 |
+
- **IPCC-compliant** emission calculations for accurate reporting
|
| 198 |
+
- **Carbon footprint tracking** with detailed analytics
|
| 199 |
+
- **ESG score improvement** through sustainability metrics
|
| 200 |
+
|
| 201 |
+
### Financial Benefits
|
| 202 |
+
- **Carbon tax savings**: Potential $1,250+ monthly savings
|
| 203 |
+
- **Regulatory compliance**: Readiness for emission regulations
|
| 204 |
+
- **Operational efficiency**: Optimized route planning
|
| 205 |
+
- **Brand reputation**: Enhanced sustainability profile
|
| 206 |
+
|
| 207 |
+
### Operational Benefits
|
| 208 |
+
- **Real-time monitoring** of emission performance
|
| 209 |
+
- **Data-driven decisions** with comprehensive analytics
|
| 210 |
+
- **Scalable solution** for growing logistics operations
|
| 211 |
+
- **Integration-ready** APIs for existing systems
|
| 212 |
+
|
| 213 |
+
## 🎨 Design Philosophy
|
| 214 |
+
|
| 215 |
+
### Eco-Friendly Theme
|
| 216 |
+
- **Primary Color**: 🌱 Green (#2ECC71) for sustainability focus
|
| 217 |
+
- **Secondary**: ⚪ Clean whites and soft greys (#F8F9FA)
|
| 218 |
+
- **Accent**: 🔵 Professional navy (#34495E) for trust
|
| 219 |
+
- **Typography**: Modern sans-serif fonts (Roboto, Inter)
|
| 220 |
+
|
| 221 |
+
### User Experience
|
| 222 |
+
- **Minimalist design** with purpose-driven interfaces
|
| 223 |
+
- **Mobile responsive** layout for all devices
|
| 224 |
+
- **Intuitive navigation** with clear visual hierarchy
|
| 225 |
+
- **Professional aesthetics** suitable for enterprise use
|
| 226 |
+
|
| 227 |
+
## 🚀 Deployment Options
|
| 228 |
+
|
| 229 |
+
### 1. Streamlit Cloud (Recommended)
|
| 230 |
+
```bash
|
| 231 |
+
# Push to GitHub and deploy via Streamlit Cloud
|
| 232 |
+
# Automatic deployment with GitHub integration
|
| 233 |
+
```
|
| 234 |
+
|
| 235 |
+
### 2. Heroku
|
| 236 |
+
```bash
|
| 237 |
+
# Deploy to Heroku with Procfile
|
| 238 |
+
echo "web: streamlit run streamlit_app.py --server.port=\$PORT --server.address=0.0.0.0" > Procfile
|
| 239 |
+
git add . && git commit -m "Deploy to Heroku"
|
| 240 |
+
heroku create your-app-name
|
| 241 |
+
git push heroku main
|
| 242 |
+
```
|
| 243 |
+
|
| 244 |
+
### 3. Docker Production
|
| 245 |
+
```bash
|
| 246 |
+
# Production deployment with Docker
|
| 247 |
+
docker-compose -f docker-compose.prod.yml up -d
|
| 248 |
+
```
|
| 249 |
+
|
| 250 |
+
## 📋 API Documentation
|
| 251 |
+
|
| 252 |
+
### FastAPI Endpoints
|
| 253 |
+
- **GET** `/` - Health check and API information
|
| 254 |
+
- **POST** `/calculate-emissions` - Calculate CO₂ emissions
|
| 255 |
+
- **GET** `/compare-transport-modes` - Compare emission factors
|
| 256 |
+
- **POST** `/optimize-route` - Get green route recommendations
|
| 257 |
+
- **POST** `/scenario-analysis` - Business impact simulation
|
| 258 |
+
- **GET** `/emission-factors` - IPCC emission factors reference
|
| 259 |
+
|
| 260 |
+
### Interactive API Docs
|
| 261 |
+
Access comprehensive API documentation at `http://localhost:8000/docs` when running the FastAPI backend.
|
| 262 |
+
|
| 263 |
+
## 🧪 Testing & Validation
|
| 264 |
+
|
| 265 |
+
### Emission Calculations
|
| 266 |
+
- **IPCC 2019 Guidelines** compliance verification
|
| 267 |
+
- **Transport mode accuracy** testing with real-world data
|
| 268 |
+
- **Carbon tax calculations** with multiple rate scenarios
|
| 269 |
+
|
| 270 |
+
### Route Optimization
|
| 271 |
+
- **Multi-modal efficiency** testing across different distances
|
| 272 |
+
- **Time penalty validation** within acceptable limits
|
| 273 |
+
- **Cost-benefit analysis** for optimization recommendations
|
| 274 |
+
|
| 275 |
+
## 🤝 Contributing
|
| 276 |
+
|
| 277 |
+
We welcome contributions to improve GreenPath! Here's how to get started:
|
| 278 |
+
|
| 279 |
+
1. **Fork the repository**
|
| 280 |
+
2. **Create a feature branch**: `git checkout -b feature/AmazingFeature`
|
| 281 |
+
3. **Commit your changes**: `git commit -m 'Add AmazingFeature'`
|
| 282 |
+
4. **Push to the branch**: `git push origin feature/AmazingFeature`
|
| 283 |
+
5. **Open a Pull Request**
|
| 284 |
+
|
| 285 |
+
### Development Guidelines
|
| 286 |
+
- Follow **PEP 8** Python style guidelines
|
| 287 |
+
- Add **comprehensive docstrings** for new functions
|
| 288 |
+
- Include **unit tests** for new features
|
| 289 |
+
- Update **documentation** for API changes
|
| 290 |
+
|
| 291 |
+
## 📄 License
|
| 292 |
+
|
| 293 |
+
This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details.
|
| 294 |
+
|
| 295 |
+
## 👨💻 Author
|
| 296 |
+
|
| 297 |
+
**Sayed Mohd Zayeem Khateeb**
|
| 298 |
+
- 🌐 **GitHub**: [@zayeemskhateeb-cloud](https://github.com/zayeemskhateeb-cloud)
|
| 299 |
+
- 💼 **LinkedIn**: [Sayed Mohd Zayeem Khateeb](https://www.linkedin.com/in/zayeemkhateeb)
|
| 300 |
+
- 📧 **Email**: [zayeem.s.khateeb@gmail.com](mailto:zayeem.s.khateeb@gmail.com)
|
| 301 |
+
|
| 302 |
+
## 🙏 Acknowledgments
|
| 303 |
+
|
| 304 |
+
- **IPCC** for emission factor guidelines and methodology
|
| 305 |
+
- **OpenRouteService** for routing and geocoding services
|
| 306 |
+
- **Streamlit** for the amazing web app framework
|
| 307 |
+
- **FastAPI** for high-performance API development
|
| 308 |
+
- **Open-source community** for excellent libraries and tools
|
| 309 |
+
|
| 310 |
+
## 🌟 Star History
|
| 311 |
+
|
| 312 |
+
If you find GreenPath helpful for your sustainability goals, please ⭐ **star this repository**!
|
| 313 |
+
|
| 314 |
+
---
|
| 315 |
+
|
| 316 |
+
<div align="center">
|
| 317 |
+
|
| 318 |
+
**🌱 GreenPath - Making Logistics Sustainable, One Route at a Time**
|
| 319 |
+
|
| 320 |
+
*Designed with ❤️ for a greener future*
|
| 321 |
+
|
| 322 |
+
</div>
|
SNOWFLAKE_DEPLOYMENT.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🌨️ Snowflake Integration for GreenPath Platform
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
|
| 5 |
+
This guide explains how to integrate Snowflake as the data warehouse backend for the GreenPath AI CO₂ Emission Reduction Platform. Snowflake will store emission data, analytics, and provide enterprise-scale data processing capabilities.
|
| 6 |
+
|
| 7 |
+
## 🏗️ Architecture
|
| 8 |
+
|
| 9 |
+
```
|
| 10 |
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
| 11 |
+
│ Streamlit │ │ FastAPI │ │ Snowflake │
|
| 12 |
+
│ Frontend │◄──►│ Backend │◄──►│ Data Warehouse │
|
| 13 |
+
│ │ │ │ │ │
|
| 14 |
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
| 15 |
+
```
|
| 16 |
+
|
| 17 |
+
## 🚀 Deployment Options
|
| 18 |
+
|
| 19 |
+
### Option 1: Snowflake as Data Backend (Recommended)
|
| 20 |
+
Deploy the web app on cloud platforms while using Snowflake for data storage:
|
| 21 |
+
|
| 22 |
+
**Web App Hosting:**
|
| 23 |
+
- **Streamlit Cloud**: Free hosting for Streamlit apps
|
| 24 |
+
- **Heroku**: Full-stack deployment
|
| 25 |
+
- **AWS/GCP/Azure**: Enterprise deployment
|
| 26 |
+
|
| 27 |
+
**Data Storage:**
|
| 28 |
+
- **Snowflake**: Enterprise data warehouse for emission data, analytics
|
| 29 |
+
|
| 30 |
+
### Option 2: Snowflake Native Apps (Advanced)
|
| 31 |
+
Deploy as a Snowflake Native App (requires Snowflake Native App Framework):
|
| 32 |
+
|
| 33 |
+
## 📋 Prerequisites
|
| 34 |
+
|
| 35 |
+
1. **Snowflake Account**: Sign up at [snowflake.com](https://snowflake.com)
|
| 36 |
+
2. **Database Setup**: Create database and schema
|
| 37 |
+
3. **Credentials**: Obtain account identifier, username, password
|
| 38 |
+
|
| 39 |
+
## 🔧 Setup Instructions
|
| 40 |
+
|
| 41 |
+
### Step 1: Snowflake Account Setup
|
| 42 |
+
|
| 43 |
+
```sql
|
| 44 |
+
-- Create database and schema
|
| 45 |
+
CREATE DATABASE GREENPATH;
|
| 46 |
+
CREATE SCHEMA GREENPATH.EMISSIONS;
|
| 47 |
+
|
| 48 |
+
-- Create warehouse
|
| 49 |
+
CREATE WAREHOUSE COMPUTE_WH WITH
|
| 50 |
+
WAREHOUSE_SIZE = 'X-SMALL'
|
| 51 |
+
AUTO_SUSPEND = 60
|
| 52 |
+
AUTO_RESUME = TRUE;
|
| 53 |
+
|
| 54 |
+
-- Grant permissions
|
| 55 |
+
GRANT USAGE ON DATABASE GREENPATH TO ROLE ACCOUNTADMIN;
|
| 56 |
+
GRANT USAGE ON SCHEMA GREENPATH.EMISSIONS TO ROLE ACCOUNTADMIN;
|
| 57 |
+
GRANT USAGE ON WAREHOUSE COMPUTE_WH TO ROLE ACCOUNTADMIN;
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
### Step 2: Environment Configuration
|
| 61 |
+
|
| 62 |
+
```bash
|
| 63 |
+
# Copy Snowflake environment template
|
| 64 |
+
cp .env.snowflake .env
|
| 65 |
+
|
| 66 |
+
# Edit .env with your Snowflake credentials
|
| 67 |
+
SNOWFLAKE_ACCOUNT=your_account.region.cloud
|
| 68 |
+
SNOWFLAKE_USER=your_username
|
| 69 |
+
SNOWFLAKE_PASSWORD=your_password
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
### Step 3: Install Dependencies
|
| 73 |
+
|
| 74 |
+
```bash
|
| 75 |
+
pip install snowflake-connector-python snowflake-sqlalchemy
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
### Step 4: Initialize Database Tables
|
| 79 |
+
|
| 80 |
+
```python
|
| 81 |
+
from src.database.snowflake_models import SnowflakeDataManager
|
| 82 |
+
|
| 83 |
+
# Initialize Snowflake connection and create tables
|
| 84 |
+
manager = SnowflakeDataManager()
|
| 85 |
+
manager.create_tables()
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
## 🌐 Deployment Scenarios
|
| 89 |
+
|
| 90 |
+
### Scenario A: Streamlit Cloud + Snowflake
|
| 91 |
+
|
| 92 |
+
1. **Deploy to Streamlit Cloud:**
|
| 93 |
+
```bash
|
| 94 |
+
# Push to GitHub
|
| 95 |
+
git add .
|
| 96 |
+
git commit -m "Add Snowflake integration"
|
| 97 |
+
git push origin main
|
| 98 |
+
|
| 99 |
+
# Deploy via Streamlit Cloud dashboard
|
| 100 |
+
# Connect GitHub repository
|
| 101 |
+
# Add Snowflake credentials to secrets
|
| 102 |
+
```
|
| 103 |
+
|
| 104 |
+
2. **Configure Secrets in Streamlit Cloud:**
|
| 105 |
+
```toml
|
| 106 |
+
# .streamlit/secrets.toml
|
| 107 |
+
[snowflake]
|
| 108 |
+
account = "your_account.region.cloud"
|
| 109 |
+
user = "your_username"
|
| 110 |
+
password = "your_password"
|
| 111 |
+
database = "GREENPATH"
|
| 112 |
+
schema = "EMISSIONS"
|
| 113 |
+
warehouse = "COMPUTE_WH"
|
| 114 |
+
```
|
| 115 |
+
|
| 116 |
+
### Scenario B: Heroku + Snowflake
|
| 117 |
+
|
| 118 |
+
1. **Create Heroku App:**
|
| 119 |
+
```bash
|
| 120 |
+
heroku create greenpath-emissions
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
2. **Set Environment Variables:**
|
| 124 |
+
```bash
|
| 125 |
+
heroku config:set SNOWFLAKE_ACCOUNT=your_account.region.cloud
|
| 126 |
+
heroku config:set SNOWFLAKE_USER=your_username
|
| 127 |
+
heroku config:set SNOWFLAKE_PASSWORD=your_password
|
| 128 |
+
heroku config:set SNOWFLAKE_DATABASE=GREENPATH
|
| 129 |
+
heroku config:set SNOWFLAKE_SCHEMA=EMISSIONS
|
| 130 |
+
heroku config:set SNOWFLAKE_WAREHOUSE=COMPUTE_WH
|
| 131 |
+
```
|
| 132 |
+
|
| 133 |
+
3. **Deploy:**
|
| 134 |
+
```bash
|
| 135 |
+
git push heroku main
|
| 136 |
+
```
|
| 137 |
+
|
| 138 |
+
### Scenario C: Docker + Snowflake
|
| 139 |
+
|
| 140 |
+
1. **Update docker-compose.yml:**
|
| 141 |
+
```yaml
|
| 142 |
+
version: '3.8'
|
| 143 |
+
services:
|
| 144 |
+
streamlit:
|
| 145 |
+
build:
|
| 146 |
+
context: .
|
| 147 |
+
dockerfile: Dockerfile.streamlit
|
| 148 |
+
ports:
|
| 149 |
+
- "8501:8501"
|
| 150 |
+
environment:
|
| 151 |
+
- SNOWFLAKE_ACCOUNT=${SNOWFLAKE_ACCOUNT}
|
| 152 |
+
- SNOWFLAKE_USER=${SNOWFLAKE_USER}
|
| 153 |
+
- SNOWFLAKE_PASSWORD=${SNOWFLAKE_PASSWORD}
|
| 154 |
+
- SNOWFLAKE_DATABASE=GREENPATH
|
| 155 |
+
- SNOWFLAKE_SCHEMA=EMISSIONS
|
| 156 |
+
- SNOWFLAKE_WAREHOUSE=COMPUTE_WH
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
2. **Deploy:**
|
| 160 |
+
```bash
|
| 161 |
+
docker-compose up --build
|
| 162 |
+
```
|
| 163 |
+
|
| 164 |
+
## 📊 Data Models
|
| 165 |
+
|
| 166 |
+
### Shipments Table
|
| 167 |
+
```sql
|
| 168 |
+
CREATE TABLE shipments (
|
| 169 |
+
id STRING PRIMARY KEY,
|
| 170 |
+
origin STRING,
|
| 171 |
+
destination STRING,
|
| 172 |
+
distance_km FLOAT,
|
| 173 |
+
weight_tonnes FLOAT,
|
| 174 |
+
transport_mode STRING,
|
| 175 |
+
co2_emissions_kg FLOAT,
|
| 176 |
+
carbon_tax_cost_usd FLOAT,
|
| 177 |
+
created_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP()
|
| 178 |
+
);
|
| 179 |
+
```
|
| 180 |
+
|
| 181 |
+
### Route Optimizations Table
|
| 182 |
+
```sql
|
| 183 |
+
CREATE TABLE route_optimizations (
|
| 184 |
+
id STRING PRIMARY KEY,
|
| 185 |
+
shipment_id STRING,
|
| 186 |
+
original_emissions_kg FLOAT,
|
| 187 |
+
optimized_emissions_kg FLOAT,
|
| 188 |
+
emission_reduction_percent FLOAT,
|
| 189 |
+
recommended_mode STRING,
|
| 190 |
+
created_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP()
|
| 191 |
+
);
|
| 192 |
+
```
|
| 193 |
+
|
| 194 |
+
## 🔍 Analytics Queries
|
| 195 |
+
|
| 196 |
+
### Monthly Emission Trends
|
| 197 |
+
```sql
|
| 198 |
+
SELECT
|
| 199 |
+
DATE_TRUNC('month', created_at) as month,
|
| 200 |
+
SUM(co2_emissions_kg) as total_emissions,
|
| 201 |
+
COUNT(*) as shipment_count,
|
| 202 |
+
AVG(co2_emissions_kg) as avg_emissions
|
| 203 |
+
FROM shipments
|
| 204 |
+
GROUP BY month
|
| 205 |
+
ORDER BY month;
|
| 206 |
+
```
|
| 207 |
+
|
| 208 |
+
### Transport Mode Comparison
|
| 209 |
+
```sql
|
| 210 |
+
SELECT
|
| 211 |
+
transport_mode,
|
| 212 |
+
SUM(co2_emissions_kg) as total_emissions,
|
| 213 |
+
COUNT(*) as shipment_count,
|
| 214 |
+
AVG(co2_emissions_kg) as avg_emissions_per_shipment
|
| 215 |
+
FROM shipments
|
| 216 |
+
GROUP BY transport_mode
|
| 217 |
+
ORDER BY total_emissions DESC;
|
| 218 |
+
```
|
| 219 |
+
|
| 220 |
+
## 🚀 Recommended Deployment
|
| 221 |
+
|
| 222 |
+
For your GreenPath platform, I recommend:
|
| 223 |
+
|
| 224 |
+
1. **Streamlit Cloud** for web app hosting (free, easy setup)
|
| 225 |
+
2. **Snowflake** for data warehouse (enterprise-grade analytics)
|
| 226 |
+
3. **GitHub** for version control and CI/CD
|
| 227 |
+
|
| 228 |
+
This combination provides:
|
| 229 |
+
- ✅ Free hosting for the web application
|
| 230 |
+
- ✅ Enterprise-grade data storage and analytics
|
| 231 |
+
- ✅ Scalable architecture
|
| 232 |
+
- ✅ Professional deployment pipeline
|
| 233 |
+
|
| 234 |
+
## 🔐 Security Best Practices
|
| 235 |
+
|
| 236 |
+
1. **Use environment variables** for all credentials
|
| 237 |
+
2. **Enable MFA** on Snowflake account
|
| 238 |
+
3. **Create dedicated service user** for application access
|
| 239 |
+
4. **Use least privilege** role assignments
|
| 240 |
+
5. **Enable network policies** if required
|
| 241 |
+
|
| 242 |
+
## 📈 Scaling Considerations
|
| 243 |
+
|
| 244 |
+
- **Warehouse Size**: Start with X-SMALL, scale as needed
|
| 245 |
+
- **Auto-suspend**: Set to 60 seconds to minimize costs
|
| 246 |
+
- **Data Retention**: Configure time travel as needed
|
| 247 |
+
- **Clustering**: Add clustering keys for large datasets
|
| 248 |
+
|
| 249 |
+
## 💰 Cost Optimization
|
| 250 |
+
|
| 251 |
+
- Use **auto-suspend** for warehouses
|
| 252 |
+
- Choose appropriate **warehouse sizes**
|
| 253 |
+
- Monitor **query performance**
|
| 254 |
+
- Use **result caching** where possible
|
| 255 |
+
|
| 256 |
+
---
|
| 257 |
+
|
| 258 |
+
**Author**: Sayed Mohd Zayeem Khateeb
|
| 259 |
+
**Contact**: zayeem.s.khateeb@gmail.com
|
app.py
CHANGED
|
@@ -1,755 +1,755 @@
|
|
| 1 |
-
"""
|
| 2 |
-
GreenPath - AI & Data Analytics Platform for Reducing Shipment CO₂ Emissions
|
| 3 |
-
Professional Streamlit Frontend with Eco-Friendly Design
|
| 4 |
-
"""
|
| 5 |
-
|
| 6 |
-
import streamlit as st
|
| 7 |
-
import pandas as pd
|
| 8 |
-
import plotly.express as px
|
| 9 |
-
import plotly.graph_objects as go
|
| 10 |
-
from plotly.subplots import make_subplots
|
| 11 |
-
import requests
|
| 12 |
-
import sys
|
| 13 |
-
import os
|
| 14 |
-
from datetime import datetime, timedelta
|
| 15 |
-
import numpy as np
|
| 16 |
-
|
| 17 |
-
# Add src directory to path
|
| 18 |
-
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
|
| 19 |
-
|
| 20 |
-
from emissions.emission_calculator import EmissionCalculator, TransportMode
|
| 21 |
-
from route_optimizer.green_route_optimizer import GreenRouteOptimizer
|
| 22 |
-
|
| 23 |
-
# Page configuration
|
| 24 |
-
st.set_page_config(
|
| 25 |
-
page_title="GreenPath - CO₂ Emission Tracker",
|
| 26 |
-
page_icon="🌱",
|
| 27 |
-
layout="wide",
|
| 28 |
-
initial_sidebar_state="expanded"
|
| 29 |
-
)
|
| 30 |
-
|
| 31 |
-
# Custom CSS for eco-friendly theme
|
| 32 |
-
st.markdown("""
|
| 33 |
-
<style>
|
| 34 |
-
|
| 35 |
-
.main-header {
|
| 36 |
-
background: linear-gradient(90deg, #2ECC71 0%, #27AE60 100%);
|
| 37 |
-
padding: 2rem;
|
| 38 |
-
border-radius: 10px;
|
| 39 |
-
color: white;
|
| 40 |
-
text-align: center;
|
| 41 |
-
margin-bottom: 2rem;
|
| 42 |
-
position: relative;
|
| 43 |
-
z-index: 1;
|
| 44 |
-
}
|
| 45 |
-
|
| 46 |
-
.metric-card {
|
| 47 |
-
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
| 48 |
-
padding: 1.5rem;
|
| 49 |
-
border-radius: 10px;
|
| 50 |
-
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
| 51 |
-
border-left: 4px solid #2ECC71;
|
| 52 |
-
margin-bottom: 1rem;
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
.green-button {
|
| 56 |
-
background-color: #2ECC71;
|
| 57 |
-
color: white;
|
| 58 |
-
border: none;
|
| 59 |
-
padding: 0.5rem 1rem;
|
| 60 |
-
border-radius: 5px;
|
| 61 |
-
cursor: pointer;
|
| 62 |
-
}
|
| 63 |
-
|
| 64 |
-
.sidebar .sidebar-content {
|
| 65 |
-
background-color: #F8F9FA;
|
| 66 |
-
}
|
| 67 |
-
|
| 68 |
-
.stSelectbox > div > div {
|
| 69 |
-
background-color: white !important;
|
| 70 |
-
border: 1px solid #E0E0E0 !important;
|
| 71 |
-
border-radius: 8px !important;
|
| 72 |
-
color: #34495E !important;
|
| 73 |
-
}
|
| 74 |
-
|
| 75 |
-
.stSelectbox > div > div > div {
|
| 76 |
-
color: #34495E !important;
|
| 77 |
-
font-weight: 500 !important;
|
| 78 |
-
}
|
| 79 |
-
|
| 80 |
-
.eco-badge {
|
| 81 |
-
background-color: #2ECC71;
|
| 82 |
-
color: white;
|
| 83 |
-
padding: 0.2rem 0.5rem;
|
| 84 |
-
border-radius: 15px;
|
| 85 |
-
font-size: 0.8rem;
|
| 86 |
-
font-weight: bold;
|
| 87 |
-
}
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
/* Navigation styling */
|
| 91 |
-
.stRadio > div {
|
| 92 |
-
background-color: transparent;
|
| 93 |
-
padding: 0.5rem;
|
| 94 |
-
border-radius: 8px;
|
| 95 |
-
}
|
| 96 |
-
|
| 97 |
-
.stRadio > div > label {
|
| 98 |
-
background-color: #FFFFFF;
|
| 99 |
-
border: 1px solid #E0E0E0;
|
| 100 |
-
border-radius: 8px;
|
| 101 |
-
margin: 4px 0;
|
| 102 |
-
padding: 8px 12px;
|
| 103 |
-
cursor: pointer;
|
| 104 |
-
transition: all 0.3s ease;
|
| 105 |
-
display: block;
|
| 106 |
-
}
|
| 107 |
-
|
| 108 |
-
.stRadio > div > label:hover {
|
| 109 |
-
background-color: #E8F5E8;
|
| 110 |
-
border-color: #2ECC71;
|
| 111 |
-
color: #2ECC71;
|
| 112 |
-
}
|
| 113 |
-
|
| 114 |
-
.stRadio > div > label > div {
|
| 115 |
-
color: #34495E !important;
|
| 116 |
-
font-size: 14px !important;
|
| 117 |
-
font-weight: 500;
|
| 118 |
-
margin: 0;
|
| 119 |
-
}
|
| 120 |
-
|
| 121 |
-
.stRadio > div > label[data-checked="true"] {
|
| 122 |
-
background-color: #2ECC71;
|
| 123 |
-
border-color: #2ECC71;
|
| 124 |
-
color: white;
|
| 125 |
-
}
|
| 126 |
-
|
| 127 |
-
.stRadio > div > label[data-checked="true"] > div {
|
| 128 |
-
color: white !important;
|
| 129 |
-
}
|
| 130 |
-
|
| 131 |
-
/* Emoji fix */
|
| 132 |
-
.stRadio label {
|
| 133 |
-
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
|
| 134 |
-
}
|
| 135 |
-
|
| 136 |
-
/* Sidebar styling */
|
| 137 |
-
.css-1d391kg {
|
| 138 |
-
background-color: #F8F9FA;
|
| 139 |
-
}
|
| 140 |
-
|
| 141 |
-
/* Metric styling */
|
| 142 |
-
[data-testid="metric-container"] {
|
| 143 |
-
background-color: white;
|
| 144 |
-
border: 1px solid #E0E0E0;
|
| 145 |
-
padding: 1rem;
|
| 146 |
-
border-radius: 8px;
|
| 147 |
-
border-left: 4px solid #2ECC71;
|
| 148 |
-
}
|
| 149 |
-
</style>
|
| 150 |
-
""", unsafe_allow_html=True)
|
| 151 |
-
|
| 152 |
-
# Initialize components
|
| 153 |
-
@st.cache_resource
|
| 154 |
-
def init_components():
|
| 155 |
-
calculator = EmissionCalculator()
|
| 156 |
-
optimizer = GreenRouteOptimizer()
|
| 157 |
-
return calculator, optimizer
|
| 158 |
-
|
| 159 |
-
calculator, optimizer = init_components()
|
| 160 |
-
|
| 161 |
-
# Header
|
| 162 |
-
st.markdown("""
|
| 163 |
-
<div class="main-header">
|
| 164 |
-
<h1>🌱 GreenPath</h1>
|
| 165 |
-
<h3>AI-Powered Platform for Reducing Shipment CO₂ Emissions</h3>
|
| 166 |
-
<p>Designed by Sayed Mohd Zayeem Khateeb</p>
|
| 167 |
-
</div>
|
| 168 |
-
""", unsafe_allow_html=True)
|
| 169 |
-
|
| 170 |
-
# Sidebar
|
| 171 |
-
with st.sidebar:
|
| 172 |
-
# Custom GreenPath logo
|
| 173 |
-
st.markdown("""
|
| 174 |
-
<div style="text-align: center; padding: 1rem; background: linear-gradient(135deg, #2ECC71, #27AE60); border-radius: 10px; margin-bottom: 1rem;">
|
| 175 |
-
<h2 style="color: white; margin: 0; font-size: 24px;">🌱 GreenPath</h2>
|
| 176 |
-
<p style="color: #E8F8F5; margin: 0; font-size: 12px;">AI Emission Tracker</p>
|
| 177 |
-
</div>
|
| 178 |
-
""", unsafe_allow_html=True)
|
| 179 |
-
|
| 180 |
-
st.markdown("### 📍 Navigate")
|
| 181 |
-
|
| 182 |
-
# Navigation with better visibility
|
| 183 |
-
nav_options = {
|
| 184 |
-
"🏠 Dashboard": "Dashboard",
|
| 185 |
-
"🧮 Emission Calculator": "Emission Calculator",
|
| 186 |
-
"🗺️ Route Optimizer": "Route Optimizer",
|
| 187 |
-
"📊 Scenario Analysis": "Scenario Analysis",
|
| 188 |
-
"📈 Analytics": "Analytics"
|
| 189 |
-
}
|
| 190 |
-
|
| 191 |
-
page = st.selectbox(
|
| 192 |
-
"Choose a page:",
|
| 193 |
-
options=list(nav_options.keys()),
|
| 194 |
-
label_visibility="collapsed",
|
| 195 |
-
key="navigation"
|
| 196 |
-
)
|
| 197 |
-
|
| 198 |
-
st.markdown("---")
|
| 199 |
-
st.markdown("### 🌍 Quick Stats")
|
| 200 |
-
|
| 201 |
-
# Sample KPIs
|
| 202 |
-
col1, col2 = st.columns(2)
|
| 203 |
-
with col1:
|
| 204 |
-
st.metric("CO₂ Saved", "2.4t", "↓ 22%")
|
| 205 |
-
with col2:
|
| 206 |
-
st.metric("Routes Optimized", "156", "↑ 15%")
|
| 207 |
-
|
| 208 |
-
# Main content based on selected page
|
| 209 |
-
if page == "🏠 Dashboard":
|
| 210 |
-
st.markdown("## 📊 Emission Overview Dashboard")
|
| 211 |
-
|
| 212 |
-
# Top KPIs
|
| 213 |
-
col1, col2, col3, col4 = st.columns(4)
|
| 214 |
-
|
| 215 |
-
with col1:
|
| 216 |
-
st.markdown("""
|
| 217 |
-
<div class="metric-card">
|
| 218 |
-
<h3 style="color: #2ECC71; margin: 0;">12.5t</h3>
|
| 219 |
-
<p style="margin: 0; color: #7F8C8D;">Total CO₂ Emissions</p>
|
| 220 |
-
<small style="color: #E74C3C;">↓ 18% vs last month</small>
|
| 221 |
-
</div>
|
| 222 |
-
""", unsafe_allow_html=True)
|
| 223 |
-
|
| 224 |
-
with col2:
|
| 225 |
-
st.markdown("""
|
| 226 |
-
<div class="metric-card">
|
| 227 |
-
<h3 style="color: #2ECC71; margin: 0;">22%</h3>
|
| 228 |
-
<p style="margin: 0; color: #7F8C8D;">Emission Reduction</p>
|
| 229 |
-
<small style="color: #27AE60;">Green routes adopted</small>
|
| 230 |
-
</div>
|
| 231 |
-
""", unsafe_allow_html=True)
|
| 232 |
-
|
| 233 |
-
with col3:
|
| 234 |
-
st.markdown("""
|
| 235 |
-
<div class="metric-card">
|
| 236 |
-
<h3 style="color: #2ECC71; margin: 0;">0.08</h3>
|
| 237 |
-
<p style="margin: 0; color: #7F8C8D;">Avg. Emission/Shipment (kg)</p>
|
| 238 |
-
<small style="color: #27AE60;">Industry best practice</small>
|
| 239 |
-
</div>
|
| 240 |
-
""", unsafe_allow_html=True)
|
| 241 |
-
|
| 242 |
-
with col4:
|
| 243 |
-
st.markdown("""
|
| 244 |
-
<div class="metric-card">
|
| 245 |
-
<h3 style="color: #2ECC71; margin: 0;">$1,250</h3>
|
| 246 |
-
<p style="margin: 0; color: #7F8C8D;">Carbon Tax Savings</p>
|
| 247 |
-
<small style="color: #27AE60;">Monthly estimate</small>
|
| 248 |
-
</div>
|
| 249 |
-
""", unsafe_allow_html=True)
|
| 250 |
-
|
| 251 |
-
# Charts
|
| 252 |
-
col1, col2 = st.columns(2)
|
| 253 |
-
|
| 254 |
-
with col1:
|
| 255 |
-
st.markdown("### 🚛 Emissions by Transport Mode")
|
| 256 |
-
|
| 257 |
-
# Sample data for transport mode comparison
|
| 258 |
-
modes_data = pd.DataFrame({
|
| 259 |
-
'Transport Mode': ['Road Truck', 'Rail', 'Ship Container', 'Air Cargo'],
|
| 260 |
-
'CO₂ Emissions (kg)': [62, 22, 11, 602],
|
| 261 |
-
'Usage %': [45, 30, 20, 5]
|
| 262 |
-
})
|
| 263 |
-
|
| 264 |
-
fig = px.bar(
|
| 265 |
-
modes_data,
|
| 266 |
-
x='Transport Mode',
|
| 267 |
-
y='CO₂ Emissions (kg)',
|
| 268 |
-
color='CO₂ Emissions (kg)',
|
| 269 |
-
color_continuous_scale=['#2ECC71', '#E74C3C'],
|
| 270 |
-
title="Emission Factors by Transport Mode"
|
| 271 |
-
)
|
| 272 |
-
fig.update_layout(showlegend=False, height=400)
|
| 273 |
-
st.plotly_chart(fig, use_container_width=True)
|
| 274 |
-
|
| 275 |
-
with col2:
|
| 276 |
-
st.markdown("### 📈 Emission Trends")
|
| 277 |
-
|
| 278 |
-
# Sample trend data
|
| 279 |
-
emissions_data = [15.2, 14.8, 13.9, 13.1, 12.8, 12.3, 11.9, 11.5, 12.5]
|
| 280 |
-
dates = pd.date_range(start='2024-01-01', periods=len(emissions_data), freq='M')
|
| 281 |
-
trend_data = pd.DataFrame({
|
| 282 |
-
'Date': dates,
|
| 283 |
-
'Emissions (tonnes)': emissions_data,
|
| 284 |
-
'Target': [14.0] * len(emissions_data)
|
| 285 |
-
})
|
| 286 |
-
|
| 287 |
-
fig = go.Figure()
|
| 288 |
-
fig.add_trace(go.Scatter(
|
| 289 |
-
x=trend_data['Date'],
|
| 290 |
-
y=trend_data['Emissions (tonnes)'],
|
| 291 |
-
mode='lines+markers',
|
| 292 |
-
name='Actual Emissions',
|
| 293 |
-
line=dict(color='#2ECC71', width=3)
|
| 294 |
-
))
|
| 295 |
-
fig.add_trace(go.Scatter(
|
| 296 |
-
x=trend_data['Date'],
|
| 297 |
-
y=trend_data['Target'],
|
| 298 |
-
mode='lines',
|
| 299 |
-
name='Target',
|
| 300 |
-
line=dict(color='#E74C3C', dash='dash')
|
| 301 |
-
))
|
| 302 |
-
fig.update_layout(title="Monthly Emission Trends", height=400)
|
| 303 |
-
st.plotly_chart(fig, use_container_width=True)
|
| 304 |
-
|
| 305 |
-
elif page == "🧮 Emission Calculator":
|
| 306 |
-
st.markdown("## 🧮 CO₂ Emission Calculator")
|
| 307 |
-
st.markdown("Calculate CO₂ emissions using the formula: **CO₂ = Distance × Weight × EmissionFactor**")
|
| 308 |
-
|
| 309 |
-
col1, col2 = st.columns([2, 1])
|
| 310 |
-
|
| 311 |
-
with col1:
|
| 312 |
-
with st.form("emission_calculator"):
|
| 313 |
-
st.markdown("### Input Parameters")
|
| 314 |
-
|
| 315 |
-
col_a, col_b = st.columns(2)
|
| 316 |
-
with col_a:
|
| 317 |
-
distance = st.number_input("Distance (km)", min_value=0.1, value=500.0, step=10.0)
|
| 318 |
-
weight = st.number_input("Weight (tonnes)", min_value=0.01, value=2.0, step=0.1)
|
| 319 |
-
|
| 320 |
-
with col_b:
|
| 321 |
-
transport_mode = st.selectbox(
|
| 322 |
-
"Transport Mode",
|
| 323 |
-
options=[mode.value for mode in TransportMode],
|
| 324 |
-
format_func=lambda x: x.replace('_', ' ').title()
|
| 325 |
-
)
|
| 326 |
-
|
| 327 |
-
calculate_btn = st.form_submit_button("🧮 Calculate Emissions", type="primary")
|
| 328 |
-
|
| 329 |
-
if calculate_btn:
|
| 330 |
-
try:
|
| 331 |
-
# Convert string to TransportMode enum
|
| 332 |
-
mode_mapping = {
|
| 333 |
-
'road_truck': TransportMode.ROAD_TRUCK,
|
| 334 |
-
'road_van': TransportMode.ROAD_VAN,
|
| 335 |
-
'rail': TransportMode.RAIL,
|
| 336 |
-
'air_cargo': TransportMode.AIR_CARGO,
|
| 337 |
-
'ship_container': TransportMode.SHIP_CONTAINER,
|
| 338 |
-
'ship_bulk': TransportMode.SHIP_BULK
|
| 339 |
-
}
|
| 340 |
-
|
| 341 |
-
if transport_mode in mode_mapping:
|
| 342 |
-
mode = mode_mapping[transport_mode]
|
| 343 |
-
else:
|
| 344 |
-
mode = TransportMode(transport_mode)
|
| 345 |
-
|
| 346 |
-
result = calculator.calculate_emissions(distance, weight, mode)
|
| 347 |
-
|
| 348 |
-
st.success("✅ Calculation Complete!")
|
| 349 |
-
|
| 350 |
-
# Results display
|
| 351 |
-
col_r1, col_r2, col_r3 = st.columns(3)
|
| 352 |
-
|
| 353 |
-
with col_r1:
|
| 354 |
-
st.metric(
|
| 355 |
-
"CO₂ Emissions",
|
| 356 |
-
f"{result['co2_emissions_kg']:.2f} kg",
|
| 357 |
-
f"{result['co2_emissions_tonnes']:.3f} tonnes"
|
| 358 |
-
)
|
| 359 |
-
|
| 360 |
-
with col_r2:
|
| 361 |
-
carbon_tax = calculator.calculate_carbon_tax_cost(result['co2_emissions_kg'])
|
| 362 |
-
st.metric(
|
| 363 |
-
"Carbon Tax Cost",
|
| 364 |
-
f"${carbon_tax['carbon_tax_cost_usd']:.2f}",
|
| 365 |
-
"@ $50/tonne CO₂"
|
| 366 |
-
)
|
| 367 |
-
|
| 368 |
-
with col_r3:
|
| 369 |
-
st.metric(
|
| 370 |
-
"Emission Factor",
|
| 371 |
-
f"{result['emission_factor']:.3f}",
|
| 372 |
-
"kg CO₂/tonne-km"
|
| 373 |
-
)
|
| 374 |
-
|
| 375 |
-
# Comparison with other modes
|
| 376 |
-
st.markdown("### 🔄 Transport Mode Comparison")
|
| 377 |
-
comparison_df = calculator.compare_transport_modes(distance, weight)
|
| 378 |
-
|
| 379 |
-
fig = px.bar(
|
| 380 |
-
comparison_df,
|
| 381 |
-
x='transport_mode',
|
| 382 |
-
y='co2_emissions_kg',
|
| 383 |
-
color='co2_emissions_kg',
|
| 384 |
-
color_continuous_scale=['#2ECC71', '#E74C3C'],
|
| 385 |
-
title="CO₂ Emissions by Transport Mode"
|
| 386 |
-
)
|
| 387 |
-
fig.update_layout(height=400)
|
| 388 |
-
st.plotly_chart(fig, use_container_width=True)
|
| 389 |
-
|
| 390 |
-
st.dataframe(comparison_df, use_container_width=True)
|
| 391 |
-
|
| 392 |
-
except Exception as e:
|
| 393 |
-
st.error(f"❌ Calculation failed: {str(e)}")
|
| 394 |
-
|
| 395 |
-
with col2:
|
| 396 |
-
st.markdown("### 📋 Emission Factors")
|
| 397 |
-
factors_df = calculator.get_emission_factors_table()
|
| 398 |
-
st.dataframe(factors_df, use_container_width=True)
|
| 399 |
-
|
| 400 |
-
st.markdown("### 🌱 Green Tips")
|
| 401 |
-
st.info("""
|
| 402 |
-
**Reduce Emissions:**
|
| 403 |
-
- Choose rail over road when possible
|
| 404 |
-
- Use container ships for long distances
|
| 405 |
-
- Optimize load capacity
|
| 406 |
-
- Consider multimodal transport
|
| 407 |
-
""")
|
| 408 |
-
|
| 409 |
-
elif page == "🗺️ Route Optimizer":
|
| 410 |
-
st.markdown("## 🗺️ Green Route Optimizer")
|
| 411 |
-
st.markdown("Find the most eco-friendly routes for your shipments")
|
| 412 |
-
|
| 413 |
-
with st.form("route_optimizer"):
|
| 414 |
-
col1, col2 = st.columns(2)
|
| 415 |
-
|
| 416 |
-
with col1:
|
| 417 |
-
origin = st.text_input("Origin", value="New York, NY", placeholder="Enter origin city")
|
| 418 |
-
destination = st.text_input("Destination", value="Los Angeles, CA", placeholder="Enter destination city")
|
| 419 |
-
|
| 420 |
-
with col2:
|
| 421 |
-
weight = st.number_input("Shipment Weight (tonnes)", min_value=0.01, value=5.0, step=0.1)
|
| 422 |
-
max_time_penalty = st.slider("Max Time Penalty (%)", 0, 50, 10)
|
| 423 |
-
|
| 424 |
-
optimize_btn = st.form_submit_button("🗺️ Find Green Routes", type="primary")
|
| 425 |
-
|
| 426 |
-
if optimize_btn and origin and destination:
|
| 427 |
-
with st.spinner("🔍 Finding optimal routes..."):
|
| 428 |
-
try:
|
| 429 |
-
# Get route recommendations
|
| 430 |
-
recommendations = optimizer.recommend_green_routes(origin, destination, weight)
|
| 431 |
-
|
| 432 |
-
if 'success' in recommendations and recommendations['success']:
|
| 433 |
-
st.success("✅ Route optimization complete!")
|
| 434 |
-
|
| 435 |
-
route_data = recommendations['recommendations']
|
| 436 |
-
|
| 437 |
-
# Display recommendations
|
| 438 |
-
st.markdown("### 🌱 Green Route Recommendations")
|
| 439 |
-
|
| 440 |
-
for i, route in enumerate(route_data):
|
| 441 |
-
with st.expander(f"Option {i+1}: {route['transport_mode'].replace('_', ' ').title()}", expanded=(i==0)):
|
| 442 |
-
col_a, col_b, col_c, col_d = st.columns(4)
|
| 443 |
-
|
| 444 |
-
with col_a:
|
| 445 |
-
st.metric("CO₂ Emissions", f"{route['co2_emissions_kg']:.1f} kg")
|
| 446 |
-
with col_b:
|
| 447 |
-
st.metric("Travel Time", f"{route['estimated_travel_time_hours']:.1f} hrs")
|
| 448 |
-
with col_c:
|
| 449 |
-
st.metric("Carbon Tax", f"${route['carbon_tax_cost_usd']:.2f}")
|
| 450 |
-
with col_d:
|
| 451 |
-
if route['emission_reduction_percent'] > 0:
|
| 452 |
-
st.metric("Emission Reduction", f"{route['emission_reduction_percent']:.1f}%", "vs worst option")
|
| 453 |
-
else:
|
| 454 |
-
st.metric("Emission Impact", "Baseline", "")
|
| 455 |
-
|
| 456 |
-
if i == 0:
|
| 457 |
-
st.markdown('<span class="eco-badge">🌱 RECOMMENDED</span>', unsafe_allow_html=True)
|
| 458 |
-
|
| 459 |
-
# Visualization
|
| 460 |
-
if len(route_data) > 1:
|
| 461 |
-
st.markdown("### 📊 Route Comparison")
|
| 462 |
-
|
| 463 |
-
df_viz = pd.DataFrame(route_data)
|
| 464 |
-
|
| 465 |
-
fig = make_subplots(
|
| 466 |
-
rows=1, cols=2,
|
| 467 |
-
subplot_titles=('CO₂ Emissions (kg)', 'Travel Time (hours)'),
|
| 468 |
-
specs=[[{"secondary_y": False}, {"secondary_y": False}]]
|
| 469 |
-
)
|
| 470 |
-
|
| 471 |
-
fig.add_trace(
|
| 472 |
-
go.Bar(
|
| 473 |
-
x=df_viz['transport_mode'],
|
| 474 |
-
y=df_viz['co2_emissions_kg'],
|
| 475 |
-
name='CO₂ Emissions',
|
| 476 |
-
marker_color='#2ECC71'
|
| 477 |
-
),
|
| 478 |
-
row=1, col=1
|
| 479 |
-
)
|
| 480 |
-
|
| 481 |
-
fig.add_trace(
|
| 482 |
-
go.Bar(
|
| 483 |
-
x=df_viz['transport_mode'],
|
| 484 |
-
y=df_viz['estimated_travel_time_hours'],
|
| 485 |
-
name='Travel Time',
|
| 486 |
-
marker_color='#3498DB'
|
| 487 |
-
),
|
| 488 |
-
row=1, col=2
|
| 489 |
-
)
|
| 490 |
-
|
| 491 |
-
fig.update_layout(height=400, showlegend=False)
|
| 492 |
-
st.plotly_chart(fig, use_container_width=True)
|
| 493 |
-
|
| 494 |
-
else:
|
| 495 |
-
st.error(f"❌ Route optimization failed: {recommendations.get('error', 'Unknown error')}")
|
| 496 |
-
|
| 497 |
-
except Exception as e:
|
| 498 |
-
st.error(f"❌ Error: {str(e)}")
|
| 499 |
-
|
| 500 |
-
elif page == "📊 Scenario Analysis":
|
| 501 |
-
st.markdown("## 📊 Business Impact Simulation")
|
| 502 |
-
st.markdown("Analyze the potential impact of adopting green shipping practices")
|
| 503 |
-
|
| 504 |
-
with st.form("scenario_analysis"):
|
| 505 |
-
col1, col2 = st.columns(2)
|
| 506 |
-
|
| 507 |
-
with col1:
|
| 508 |
-
st.markdown("### 📦 Shipment Parameters")
|
| 509 |
-
total_shipments = st.number_input("Total Monthly Shipments", min_value=1, value=1000, step=50)
|
| 510 |
-
avg_distance = st.number_input("Average Distance (km)", min_value=1.0, value=800.0, step=50.0)
|
| 511 |
-
avg_weight = st.number_input("Average Weight (tonnes)", min_value=0.1, value=3.0, step=0.1)
|
| 512 |
-
|
| 513 |
-
with col2:
|
| 514 |
-
st.markdown("### ⚙️ Optimization Parameters")
|
| 515 |
-
optimization_percent = st.slider("% Shipments Using Green Routes", 0, 100, 50)
|
| 516 |
-
current_mode = st.selectbox("Current Transport Mode", [mode.value for mode in TransportMode], index=0)
|
| 517 |
-
carbon_tax_rate = st.number_input("Carbon Tax Rate ($/tonne CO₂)", min_value=0.0, value=50.0, step=5.0)
|
| 518 |
-
|
| 519 |
-
analyze_btn = st.form_submit_button("📊 Run Scenario Analysis", type="primary")
|
| 520 |
-
|
| 521 |
-
if analyze_btn:
|
| 522 |
-
with st.spinner("🔄 Running business impact simulation..."):
|
| 523 |
-
try:
|
| 524 |
-
# Current emissions - use same mapping as before
|
| 525 |
-
mode_mapping = {
|
| 526 |
-
'road_truck': TransportMode.ROAD_TRUCK,
|
| 527 |
-
'road_van': TransportMode.ROAD_VAN,
|
| 528 |
-
'rail': TransportMode.RAIL,
|
| 529 |
-
'air_cargo': TransportMode.AIR_CARGO,
|
| 530 |
-
'ship_container': TransportMode.SHIP_CONTAINER,
|
| 531 |
-
'ship_bulk': TransportMode.SHIP_BULK
|
| 532 |
-
}
|
| 533 |
-
|
| 534 |
-
if current_mode in mode_mapping:
|
| 535 |
-
current_mode_enum = mode_mapping[current_mode]
|
| 536 |
-
else:
|
| 537 |
-
current_mode_enum = TransportMode(current_mode)
|
| 538 |
-
|
| 539 |
-
current_emissions = calculator.calculate_emissions(avg_distance, avg_weight, current_mode_enum)
|
| 540 |
-
|
| 541 |
-
# Find best green alternative - calculate manually to avoid EmissionOptimizer import
|
| 542 |
-
available_modes = [TransportMode.ROAD_TRUCK, TransportMode.RAIL, TransportMode.SHIP_CONTAINER]
|
| 543 |
-
|
| 544 |
-
# Calculate emissions for each mode and find the greenest
|
| 545 |
-
mode_options = []
|
| 546 |
-
for mode in available_modes:
|
| 547 |
-
emissions = calculator.calculate_emissions(avg_distance, avg_weight, mode)
|
| 548 |
-
mode_options.append({
|
| 549 |
-
'mode': mode,
|
| 550 |
-
'co2_emissions_kg': emissions['co2_emissions_kg'],
|
| 551 |
-
'emission_factor': emissions['emission_factor']
|
| 552 |
-
})
|
| 553 |
-
|
| 554 |
-
# Sort by emissions (lowest first) to find greenest option
|
| 555 |
-
mode_options.sort(key=lambda x: x['co2_emissions_kg'])
|
| 556 |
-
green_option = mode_options[0] if mode_options else None
|
| 557 |
-
|
| 558 |
-
if not green_option:
|
| 559 |
-
st.error("❌ No green alternatives available")
|
| 560 |
-
st.stop()
|
| 561 |
-
|
| 562 |
-
# Calculate scenario impact
|
| 563 |
-
optimized_shipments = int(total_shipments * optimization_percent / 100)
|
| 564 |
-
regular_shipments = total_shipments - optimized_shipments
|
| 565 |
-
|
| 566 |
-
current_total = current_emissions['co2_emissions_kg'] * total_shipments
|
| 567 |
-
optimized_total = (
|
| 568 |
-
green_option['co2_emissions_kg'] * optimized_shipments +
|
| 569 |
-
current_emissions['co2_emissions_kg'] * regular_shipments
|
| 570 |
-
)
|
| 571 |
-
|
| 572 |
-
savings_kg = current_total - optimized_total
|
| 573 |
-
savings_percent = (savings_kg / current_total) * 100
|
| 574 |
-
carbon_tax_savings = (savings_kg / 1000) * carbon_tax_rate
|
| 575 |
-
|
| 576 |
-
st.success("✅ Scenario analysis complete!")
|
| 577 |
-
|
| 578 |
-
# Results
|
| 579 |
-
col1, col2, col3, col4 = st.columns(4)
|
| 580 |
-
|
| 581 |
-
with col1:
|
| 582 |
-
st.metric("Current Emissions", f"{current_total/1000:.1f} tonnes/month")
|
| 583 |
-
with col2:
|
| 584 |
-
st.metric("Optimized Emissions", f"{optimized_total/1000:.1f} tonnes/month")
|
| 585 |
-
with col3:
|
| 586 |
-
st.metric("CO₂ Savings", f"{savings_kg/1000:.1f} tonnes/month", f"{savings_percent:.1f}% reduction")
|
| 587 |
-
with col4:
|
| 588 |
-
st.metric("Carbon Tax Savings", f"${carbon_tax_savings:.0f}/month", f"${carbon_tax_savings*12:.0f}/year")
|
| 589 |
-
|
| 590 |
-
# Visualization
|
| 591 |
-
st.markdown("### 📈 Impact Visualization")
|
| 592 |
-
|
| 593 |
-
scenario_data = pd.DataFrame({
|
| 594 |
-
'Scenario': ['Current', 'Optimized'],
|
| 595 |
-
'CO₂ Emissions (tonnes)': [current_total/1000, optimized_total/1000],
|
| 596 |
-
'Carbon Tax Cost ($)': [
|
| 597 |
-
(current_total/1000) * carbon_tax_rate,
|
| 598 |
-
(optimized_total/1000) * carbon_tax_rate
|
| 599 |
-
]
|
| 600 |
-
})
|
| 601 |
-
|
| 602 |
-
fig = make_subplots(
|
| 603 |
-
rows=1, cols=2,
|
| 604 |
-
subplot_titles=('CO₂ Emissions', 'Carbon Tax Cost'),
|
| 605 |
-
specs=[[{"secondary_y": False}, {"secondary_y": False}]]
|
| 606 |
-
)
|
| 607 |
-
|
| 608 |
-
fig.add_trace(
|
| 609 |
-
go.Bar(
|
| 610 |
-
x=scenario_data['Scenario'],
|
| 611 |
-
y=scenario_data['CO₂ Emissions (tonnes)'],
|
| 612 |
-
name='CO₂ Emissions',
|
| 613 |
-
marker_color=['#E74C3C', '#2ECC71']
|
| 614 |
-
),
|
| 615 |
-
row=1, col=1
|
| 616 |
-
)
|
| 617 |
-
|
| 618 |
-
fig.add_trace(
|
| 619 |
-
go.Bar(
|
| 620 |
-
x=scenario_data['Scenario'],
|
| 621 |
-
y=scenario_data['Carbon Tax Cost ($)'],
|
| 622 |
-
name='Carbon Tax Cost',
|
| 623 |
-
marker_color=['#E74C3C', '#2ECC71']
|
| 624 |
-
),
|
| 625 |
-
row=1, col=2
|
| 626 |
-
)
|
| 627 |
-
|
| 628 |
-
fig.update_layout(height=400, showlegend=False)
|
| 629 |
-
st.plotly_chart(fig, use_container_width=True)
|
| 630 |
-
|
| 631 |
-
# Business benefits
|
| 632 |
-
st.markdown("### 💼 Business Benefits")
|
| 633 |
-
|
| 634 |
-
benefits_col1, benefits_col2 = st.columns(2)
|
| 635 |
-
|
| 636 |
-
with benefits_col1:
|
| 637 |
-
st.markdown("""
|
| 638 |
-
**Environmental Impact:**
|
| 639 |
-
- ♻️ Reduced carbon footprint
|
| 640 |
-
- 🌱 Enhanced sustainability profile
|
| 641 |
-
- 📊 ESG score improvement
|
| 642 |
-
- 🏆 Industry leadership positioning
|
| 643 |
-
""")
|
| 644 |
-
|
| 645 |
-
with benefits_col2:
|
| 646 |
-
st.markdown(f"""
|
| 647 |
-
**Financial Benefits:**
|
| 648 |
-
- 💰 ${carbon_tax_savings*12:.0f} annual tax savings
|
| 649 |
-
- 📈 Potential green financing access
|
| 650 |
-
- 🎯 Regulatory compliance readiness
|
| 651 |
-
- 💡 Operational efficiency gains
|
| 652 |
-
""")
|
| 653 |
-
|
| 654 |
-
except Exception as e:
|
| 655 |
-
st.error(f"❌ Analysis failed: {str(e)}")
|
| 656 |
-
st.write(f"Debug info: {type(e).__name__}: {e}")
|
| 657 |
-
import traceback
|
| 658 |
-
st.code(traceback.format_exc())
|
| 659 |
-
|
| 660 |
-
elif page == "📈 Analytics":
|
| 661 |
-
st.markdown("## 📈 Advanced Analytics")
|
| 662 |
-
|
| 663 |
-
# Sample analytics data
|
| 664 |
-
st.markdown("### 🎯 Performance Metrics")
|
| 665 |
-
|
| 666 |
-
col1, col2, col3 = st.columns(3)
|
| 667 |
-
|
| 668 |
-
with col1:
|
| 669 |
-
st.markdown("""
|
| 670 |
-
<div class="metric-card">
|
| 671 |
-
<h4 style="color: #2ECC71; margin: 0;">Route Efficiency Score</h4>
|
| 672 |
-
<h2 style="margin: 0;">87/100</h2>
|
| 673 |
-
<p style="margin: 0; color: #7F8C8D;">Above industry average</p>
|
| 674 |
-
</div>
|
| 675 |
-
""", unsafe_allow_html=True)
|
| 676 |
-
|
| 677 |
-
with col2:
|
| 678 |
-
st.markdown("""
|
| 679 |
-
<div class="metric-card">
|
| 680 |
-
<h4 style="color: #2ECC71; margin: 0;">Green Route Adoption</h4>
|
| 681 |
-
<h2 style="margin: 0;">68%</h2>
|
| 682 |
-
<p style="margin: 0; color: #7F8C8D;">Target: 75%</p>
|
| 683 |
-
</div>
|
| 684 |
-
""", unsafe_allow_html=True)
|
| 685 |
-
|
| 686 |
-
with col3:
|
| 687 |
-
st.markdown("""
|
| 688 |
-
<div class="metric-card">
|
| 689 |
-
<h4 style="color: #2ECC71; margin: 0;">Emission Intensity</h4>
|
| 690 |
-
<h2 style="margin: 0;">0.045</h2>
|
| 691 |
-
<p style="margin: 0; color: #7F8C8D;">kg CO₂/tonne-km</p>
|
| 692 |
-
</div>
|
| 693 |
-
""", unsafe_allow_html=True)
|
| 694 |
-
|
| 695 |
-
# Regional analysis
|
| 696 |
-
st.markdown("### 🌍 Regional Emission Analysis")
|
| 697 |
-
|
| 698 |
-
regional_data = pd.DataFrame({
|
| 699 |
-
'Region': ['North America', 'Europe', 'Asia Pacific', 'Latin America'],
|
| 700 |
-
'Emissions (tonnes)': [45.2, 32.1, 28.7, 15.3],
|
| 701 |
-
'Shipments': [450, 320, 380, 180],
|
| 702 |
-
'Avg Distance (km)': [1200, 800, 950, 600]
|
| 703 |
-
})
|
| 704 |
-
|
| 705 |
-
fig = px.scatter(
|
| 706 |
-
regional_data,
|
| 707 |
-
x='Shipments',
|
| 708 |
-
y='Emissions (tonnes)',
|
| 709 |
-
size='Avg Distance (km)',
|
| 710 |
-
color='Region',
|
| 711 |
-
title="Regional Emission vs Shipment Volume"
|
| 712 |
-
)
|
| 713 |
-
fig.update_layout(height=500)
|
| 714 |
-
st.plotly_chart(fig, use_container_width=True)
|
| 715 |
-
|
| 716 |
-
st.dataframe(regional_data, use_container_width=True)
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
# Footer
|
| 720 |
-
st.markdown("---")
|
| 721 |
-
st.markdown("## 👨💻 Developer Details")
|
| 722 |
-
st.markdown("""
|
| 723 |
-
<div style="text-align: center; color: #2C3E50; padding: 2rem; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
|
| 724 |
-
<div style="margin-bottom: 1rem;">
|
| 725 |
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" style="width: 60px; height: 60px;">
|
| 726 |
-
<defs>
|
| 727 |
-
<linearGradient id="zkGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
| 728 |
-
<stop offset="0%" style="stop-color:#2ECC71;stop-opacity:1" />
|
| 729 |
-
<stop offset="100%" style="stop-color:#27AE60;stop-opacity:1" />
|
| 730 |
-
</linearGradient>
|
| 731 |
-
</defs>
|
| 732 |
-
<g transform="translate(50, 50)">
|
| 733 |
-
<path d="M10 20 L70 20 L70 35 L35 75 L70 75 L70 90 L10 90 L10 75 L45 35 L10 35 Z"
|
| 734 |
-
fill="url(#zkGradient)"
|
| 735 |
-
stroke="#1E8449"
|
| 736 |
-
stroke-width="1"/>
|
| 737 |
-
<path d="M80 20 L95 20 L95 50 L110 20 L130 20 L110 55 L130 90 L110 90 L95 65 L95 90 L80 90 Z"
|
| 738 |
-
fill="url(#zkGradient)"
|
| 739 |
-
stroke="#1E8449"
|
| 740 |
-
stroke-width="1"/>
|
| 741 |
-
</g>
|
| 742 |
-
</svg>
|
| 743 |
-
</div>
|
| 744 |
-
<p style="font-size: 1.2rem; color: #2C3E50; margin-bottom: 0.5rem;"><strong>GreenPath</strong> - AI-Powered CO₂ Emission Reduction Platform</p>
|
| 745 |
-
<p style="font-size: 1.1rem; color: #34495E; margin-bottom: 1rem;">Designed and Developed by <strong>Sayed Mohd Zayeem Khateeb</strong></p>
|
| 746 |
-
<div style="margin: 1rem 0;">
|
| 747 |
-
<a href="https://github.com/zayeemskhateeb-cloud" target="_blank" style="margin: 0 10px; text-decoration: none; color: #2ECC71; font-weight: bold; font-size: 1rem;">🌐 GitHub</a> |
|
| 748 |
-
<a href="https://www.linkedin.com/in/zayeemkhateeb" target="_blank" style="margin: 0 10px; text-decoration: none; color: #2ECC71; font-weight: bold; font-size: 1rem;">💼 LinkedIn</a> |
|
| 749 |
-
<a href="mailto:zayeem.s.khateeb@gmail.com" style="margin: 0 10px; text-decoration: none; color: #2ECC71; font-weight: bold; font-size: 1rem;">📧 Email</a>
|
| 750 |
-
</div>
|
| 751 |
-
<p style="font-size: 1rem; color: #7F8C8D; margin-top: 1rem;">
|
| 752 |
-
Specialized in AI/ML, Data Analytics, and Sustainable Technology Solutions
|
| 753 |
-
</p>
|
| 754 |
-
</div>
|
| 755 |
-
""", unsafe_allow_html=True)
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
GreenPath - AI & Data Analytics Platform for Reducing Shipment CO₂ Emissions
|
| 3 |
+
Professional Streamlit Frontend with Eco-Friendly Design
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import streamlit as st
|
| 7 |
+
import pandas as pd
|
| 8 |
+
import plotly.express as px
|
| 9 |
+
import plotly.graph_objects as go
|
| 10 |
+
from plotly.subplots import make_subplots
|
| 11 |
+
import requests
|
| 12 |
+
import sys
|
| 13 |
+
import os
|
| 14 |
+
from datetime import datetime, timedelta
|
| 15 |
+
import numpy as np
|
| 16 |
+
|
| 17 |
+
# Add src directory to path
|
| 18 |
+
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
|
| 19 |
+
|
| 20 |
+
from emissions.emission_calculator import EmissionCalculator, TransportMode
|
| 21 |
+
from route_optimizer.green_route_optimizer import GreenRouteOptimizer
|
| 22 |
+
|
| 23 |
+
# Page configuration
|
| 24 |
+
st.set_page_config(
|
| 25 |
+
page_title="GreenPath - CO₂ Emission Tracker",
|
| 26 |
+
page_icon="🌱",
|
| 27 |
+
layout="wide",
|
| 28 |
+
initial_sidebar_state="expanded"
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
# Custom CSS for eco-friendly theme
|
| 32 |
+
st.markdown("""
|
| 33 |
+
<style>
|
| 34 |
+
|
| 35 |
+
.main-header {
|
| 36 |
+
background: linear-gradient(90deg, #2ECC71 0%, #27AE60 100%);
|
| 37 |
+
padding: 2rem;
|
| 38 |
+
border-radius: 10px;
|
| 39 |
+
color: white;
|
| 40 |
+
text-align: center;
|
| 41 |
+
margin-bottom: 2rem;
|
| 42 |
+
position: relative;
|
| 43 |
+
z-index: 1;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
.metric-card {
|
| 47 |
+
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
| 48 |
+
padding: 1.5rem;
|
| 49 |
+
border-radius: 10px;
|
| 50 |
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
| 51 |
+
border-left: 4px solid #2ECC71;
|
| 52 |
+
margin-bottom: 1rem;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
.green-button {
|
| 56 |
+
background-color: #2ECC71;
|
| 57 |
+
color: white;
|
| 58 |
+
border: none;
|
| 59 |
+
padding: 0.5rem 1rem;
|
| 60 |
+
border-radius: 5px;
|
| 61 |
+
cursor: pointer;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
.sidebar .sidebar-content {
|
| 65 |
+
background-color: #F8F9FA;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
.stSelectbox > div > div {
|
| 69 |
+
background-color: white !important;
|
| 70 |
+
border: 1px solid #E0E0E0 !important;
|
| 71 |
+
border-radius: 8px !important;
|
| 72 |
+
color: #34495E !important;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
.stSelectbox > div > div > div {
|
| 76 |
+
color: #34495E !important;
|
| 77 |
+
font-weight: 500 !important;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
.eco-badge {
|
| 81 |
+
background-color: #2ECC71;
|
| 82 |
+
color: white;
|
| 83 |
+
padding: 0.2rem 0.5rem;
|
| 84 |
+
border-radius: 15px;
|
| 85 |
+
font-size: 0.8rem;
|
| 86 |
+
font-weight: bold;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
/* Navigation styling */
|
| 91 |
+
.stRadio > div {
|
| 92 |
+
background-color: transparent;
|
| 93 |
+
padding: 0.5rem;
|
| 94 |
+
border-radius: 8px;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
.stRadio > div > label {
|
| 98 |
+
background-color: #FFFFFF;
|
| 99 |
+
border: 1px solid #E0E0E0;
|
| 100 |
+
border-radius: 8px;
|
| 101 |
+
margin: 4px 0;
|
| 102 |
+
padding: 8px 12px;
|
| 103 |
+
cursor: pointer;
|
| 104 |
+
transition: all 0.3s ease;
|
| 105 |
+
display: block;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
.stRadio > div > label:hover {
|
| 109 |
+
background-color: #E8F5E8;
|
| 110 |
+
border-color: #2ECC71;
|
| 111 |
+
color: #2ECC71;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
.stRadio > div > label > div {
|
| 115 |
+
color: #34495E !important;
|
| 116 |
+
font-size: 14px !important;
|
| 117 |
+
font-weight: 500;
|
| 118 |
+
margin: 0;
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
.stRadio > div > label[data-checked="true"] {
|
| 122 |
+
background-color: #2ECC71;
|
| 123 |
+
border-color: #2ECC71;
|
| 124 |
+
color: white;
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
.stRadio > div > label[data-checked="true"] > div {
|
| 128 |
+
color: white !important;
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
/* Emoji fix */
|
| 132 |
+
.stRadio label {
|
| 133 |
+
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
/* Sidebar styling */
|
| 137 |
+
.css-1d391kg {
|
| 138 |
+
background-color: #F8F9FA;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
/* Metric styling */
|
| 142 |
+
[data-testid="metric-container"] {
|
| 143 |
+
background-color: white;
|
| 144 |
+
border: 1px solid #E0E0E0;
|
| 145 |
+
padding: 1rem;
|
| 146 |
+
border-radius: 8px;
|
| 147 |
+
border-left: 4px solid #2ECC71;
|
| 148 |
+
}
|
| 149 |
+
</style>
|
| 150 |
+
""", unsafe_allow_html=True)
|
| 151 |
+
|
| 152 |
+
# Initialize components
|
| 153 |
+
@st.cache_resource
|
| 154 |
+
def init_components():
|
| 155 |
+
calculator = EmissionCalculator()
|
| 156 |
+
optimizer = GreenRouteOptimizer()
|
| 157 |
+
return calculator, optimizer
|
| 158 |
+
|
| 159 |
+
calculator, optimizer = init_components()
|
| 160 |
+
|
| 161 |
+
# Header
|
| 162 |
+
st.markdown("""
|
| 163 |
+
<div class="main-header">
|
| 164 |
+
<h1>🌱 GreenPath</h1>
|
| 165 |
+
<h3>AI-Powered Platform for Reducing Shipment CO₂ Emissions</h3>
|
| 166 |
+
<p>Designed by Sayed Mohd Zayeem Khateeb</p>
|
| 167 |
+
</div>
|
| 168 |
+
""", unsafe_allow_html=True)
|
| 169 |
+
|
| 170 |
+
# Sidebar
|
| 171 |
+
with st.sidebar:
|
| 172 |
+
# Custom GreenPath logo
|
| 173 |
+
st.markdown("""
|
| 174 |
+
<div style="text-align: center; padding: 1rem; background: linear-gradient(135deg, #2ECC71, #27AE60); border-radius: 10px; margin-bottom: 1rem;">
|
| 175 |
+
<h2 style="color: white; margin: 0; font-size: 24px;">🌱 GreenPath</h2>
|
| 176 |
+
<p style="color: #E8F8F5; margin: 0; font-size: 12px;">AI Emission Tracker</p>
|
| 177 |
+
</div>
|
| 178 |
+
""", unsafe_allow_html=True)
|
| 179 |
+
|
| 180 |
+
st.markdown("### 📍 Navigate")
|
| 181 |
+
|
| 182 |
+
# Navigation with better visibility
|
| 183 |
+
nav_options = {
|
| 184 |
+
"🏠 Dashboard": "Dashboard",
|
| 185 |
+
"🧮 Emission Calculator": "Emission Calculator",
|
| 186 |
+
"🗺️ Route Optimizer": "Route Optimizer",
|
| 187 |
+
"📊 Scenario Analysis": "Scenario Analysis",
|
| 188 |
+
"📈 Analytics": "Analytics"
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
page = st.selectbox(
|
| 192 |
+
"Choose a page:",
|
| 193 |
+
options=list(nav_options.keys()),
|
| 194 |
+
label_visibility="collapsed",
|
| 195 |
+
key="navigation"
|
| 196 |
+
)
|
| 197 |
+
|
| 198 |
+
st.markdown("---")
|
| 199 |
+
st.markdown("### 🌍 Quick Stats")
|
| 200 |
+
|
| 201 |
+
# Sample KPIs
|
| 202 |
+
col1, col2 = st.columns(2)
|
| 203 |
+
with col1:
|
| 204 |
+
st.metric("CO₂ Saved", "2.4t", "↓ 22%")
|
| 205 |
+
with col2:
|
| 206 |
+
st.metric("Routes Optimized", "156", "↑ 15%")
|
| 207 |
+
|
| 208 |
+
# Main content based on selected page
|
| 209 |
+
if page == "🏠 Dashboard":
|
| 210 |
+
st.markdown("## 📊 Emission Overview Dashboard")
|
| 211 |
+
|
| 212 |
+
# Top KPIs
|
| 213 |
+
col1, col2, col3, col4 = st.columns(4)
|
| 214 |
+
|
| 215 |
+
with col1:
|
| 216 |
+
st.markdown("""
|
| 217 |
+
<div class="metric-card">
|
| 218 |
+
<h3 style="color: #2ECC71; margin: 0;">12.5t</h3>
|
| 219 |
+
<p style="margin: 0; color: #7F8C8D;">Total CO₂ Emissions</p>
|
| 220 |
+
<small style="color: #E74C3C;">↓ 18% vs last month</small>
|
| 221 |
+
</div>
|
| 222 |
+
""", unsafe_allow_html=True)
|
| 223 |
+
|
| 224 |
+
with col2:
|
| 225 |
+
st.markdown("""
|
| 226 |
+
<div class="metric-card">
|
| 227 |
+
<h3 style="color: #2ECC71; margin: 0;">22%</h3>
|
| 228 |
+
<p style="margin: 0; color: #7F8C8D;">Emission Reduction</p>
|
| 229 |
+
<small style="color: #27AE60;">Green routes adopted</small>
|
| 230 |
+
</div>
|
| 231 |
+
""", unsafe_allow_html=True)
|
| 232 |
+
|
| 233 |
+
with col3:
|
| 234 |
+
st.markdown("""
|
| 235 |
+
<div class="metric-card">
|
| 236 |
+
<h3 style="color: #2ECC71; margin: 0;">0.08</h3>
|
| 237 |
+
<p style="margin: 0; color: #7F8C8D;">Avg. Emission/Shipment (kg)</p>
|
| 238 |
+
<small style="color: #27AE60;">Industry best practice</small>
|
| 239 |
+
</div>
|
| 240 |
+
""", unsafe_allow_html=True)
|
| 241 |
+
|
| 242 |
+
with col4:
|
| 243 |
+
st.markdown("""
|
| 244 |
+
<div class="metric-card">
|
| 245 |
+
<h3 style="color: #2ECC71; margin: 0;">$1,250</h3>
|
| 246 |
+
<p style="margin: 0; color: #7F8C8D;">Carbon Tax Savings</p>
|
| 247 |
+
<small style="color: #27AE60;">Monthly estimate</small>
|
| 248 |
+
</div>
|
| 249 |
+
""", unsafe_allow_html=True)
|
| 250 |
+
|
| 251 |
+
# Charts
|
| 252 |
+
col1, col2 = st.columns(2)
|
| 253 |
+
|
| 254 |
+
with col1:
|
| 255 |
+
st.markdown("### 🚛 Emissions by Transport Mode")
|
| 256 |
+
|
| 257 |
+
# Sample data for transport mode comparison
|
| 258 |
+
modes_data = pd.DataFrame({
|
| 259 |
+
'Transport Mode': ['Road Truck', 'Rail', 'Ship Container', 'Air Cargo'],
|
| 260 |
+
'CO₂ Emissions (kg)': [62, 22, 11, 602],
|
| 261 |
+
'Usage %': [45, 30, 20, 5]
|
| 262 |
+
})
|
| 263 |
+
|
| 264 |
+
fig = px.bar(
|
| 265 |
+
modes_data,
|
| 266 |
+
x='Transport Mode',
|
| 267 |
+
y='CO₂ Emissions (kg)',
|
| 268 |
+
color='CO₂ Emissions (kg)',
|
| 269 |
+
color_continuous_scale=['#2ECC71', '#E74C3C'],
|
| 270 |
+
title="Emission Factors by Transport Mode"
|
| 271 |
+
)
|
| 272 |
+
fig.update_layout(showlegend=False, height=400)
|
| 273 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 274 |
+
|
| 275 |
+
with col2:
|
| 276 |
+
st.markdown("### 📈 Emission Trends")
|
| 277 |
+
|
| 278 |
+
# Sample trend data
|
| 279 |
+
emissions_data = [15.2, 14.8, 13.9, 13.1, 12.8, 12.3, 11.9, 11.5, 12.5]
|
| 280 |
+
dates = pd.date_range(start='2024-01-01', periods=len(emissions_data), freq='M')
|
| 281 |
+
trend_data = pd.DataFrame({
|
| 282 |
+
'Date': dates,
|
| 283 |
+
'Emissions (tonnes)': emissions_data,
|
| 284 |
+
'Target': [14.0] * len(emissions_data)
|
| 285 |
+
})
|
| 286 |
+
|
| 287 |
+
fig = go.Figure()
|
| 288 |
+
fig.add_trace(go.Scatter(
|
| 289 |
+
x=trend_data['Date'],
|
| 290 |
+
y=trend_data['Emissions (tonnes)'],
|
| 291 |
+
mode='lines+markers',
|
| 292 |
+
name='Actual Emissions',
|
| 293 |
+
line=dict(color='#2ECC71', width=3)
|
| 294 |
+
))
|
| 295 |
+
fig.add_trace(go.Scatter(
|
| 296 |
+
x=trend_data['Date'],
|
| 297 |
+
y=trend_data['Target'],
|
| 298 |
+
mode='lines',
|
| 299 |
+
name='Target',
|
| 300 |
+
line=dict(color='#E74C3C', dash='dash')
|
| 301 |
+
))
|
| 302 |
+
fig.update_layout(title="Monthly Emission Trends", height=400)
|
| 303 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 304 |
+
|
| 305 |
+
elif page == "🧮 Emission Calculator":
|
| 306 |
+
st.markdown("## 🧮 CO₂ Emission Calculator")
|
| 307 |
+
st.markdown("Calculate CO₂ emissions using the formula: **CO₂ = Distance × Weight × EmissionFactor**")
|
| 308 |
+
|
| 309 |
+
col1, col2 = st.columns([2, 1])
|
| 310 |
+
|
| 311 |
+
with col1:
|
| 312 |
+
with st.form("emission_calculator"):
|
| 313 |
+
st.markdown("### Input Parameters")
|
| 314 |
+
|
| 315 |
+
col_a, col_b = st.columns(2)
|
| 316 |
+
with col_a:
|
| 317 |
+
distance = st.number_input("Distance (km)", min_value=0.1, value=500.0, step=10.0)
|
| 318 |
+
weight = st.number_input("Weight (tonnes)", min_value=0.01, value=2.0, step=0.1)
|
| 319 |
+
|
| 320 |
+
with col_b:
|
| 321 |
+
transport_mode = st.selectbox(
|
| 322 |
+
"Transport Mode",
|
| 323 |
+
options=[mode.value for mode in TransportMode],
|
| 324 |
+
format_func=lambda x: x.replace('_', ' ').title()
|
| 325 |
+
)
|
| 326 |
+
|
| 327 |
+
calculate_btn = st.form_submit_button("🧮 Calculate Emissions", type="primary")
|
| 328 |
+
|
| 329 |
+
if calculate_btn:
|
| 330 |
+
try:
|
| 331 |
+
# Convert string to TransportMode enum
|
| 332 |
+
mode_mapping = {
|
| 333 |
+
'road_truck': TransportMode.ROAD_TRUCK,
|
| 334 |
+
'road_van': TransportMode.ROAD_VAN,
|
| 335 |
+
'rail': TransportMode.RAIL,
|
| 336 |
+
'air_cargo': TransportMode.AIR_CARGO,
|
| 337 |
+
'ship_container': TransportMode.SHIP_CONTAINER,
|
| 338 |
+
'ship_bulk': TransportMode.SHIP_BULK
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
if transport_mode in mode_mapping:
|
| 342 |
+
mode = mode_mapping[transport_mode]
|
| 343 |
+
else:
|
| 344 |
+
mode = TransportMode(transport_mode)
|
| 345 |
+
|
| 346 |
+
result = calculator.calculate_emissions(distance, weight, mode)
|
| 347 |
+
|
| 348 |
+
st.success("✅ Calculation Complete!")
|
| 349 |
+
|
| 350 |
+
# Results display
|
| 351 |
+
col_r1, col_r2, col_r3 = st.columns(3)
|
| 352 |
+
|
| 353 |
+
with col_r1:
|
| 354 |
+
st.metric(
|
| 355 |
+
"CO₂ Emissions",
|
| 356 |
+
f"{result['co2_emissions_kg']:.2f} kg",
|
| 357 |
+
f"{result['co2_emissions_tonnes']:.3f} tonnes"
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
with col_r2:
|
| 361 |
+
carbon_tax = calculator.calculate_carbon_tax_cost(result['co2_emissions_kg'])
|
| 362 |
+
st.metric(
|
| 363 |
+
"Carbon Tax Cost",
|
| 364 |
+
f"${carbon_tax['carbon_tax_cost_usd']:.2f}",
|
| 365 |
+
"@ $50/tonne CO₂"
|
| 366 |
+
)
|
| 367 |
+
|
| 368 |
+
with col_r3:
|
| 369 |
+
st.metric(
|
| 370 |
+
"Emission Factor",
|
| 371 |
+
f"{result['emission_factor']:.3f}",
|
| 372 |
+
"kg CO₂/tonne-km"
|
| 373 |
+
)
|
| 374 |
+
|
| 375 |
+
# Comparison with other modes
|
| 376 |
+
st.markdown("### 🔄 Transport Mode Comparison")
|
| 377 |
+
comparison_df = calculator.compare_transport_modes(distance, weight)
|
| 378 |
+
|
| 379 |
+
fig = px.bar(
|
| 380 |
+
comparison_df,
|
| 381 |
+
x='transport_mode',
|
| 382 |
+
y='co2_emissions_kg',
|
| 383 |
+
color='co2_emissions_kg',
|
| 384 |
+
color_continuous_scale=['#2ECC71', '#E74C3C'],
|
| 385 |
+
title="CO₂ Emissions by Transport Mode"
|
| 386 |
+
)
|
| 387 |
+
fig.update_layout(height=400)
|
| 388 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 389 |
+
|
| 390 |
+
st.dataframe(comparison_df, use_container_width=True)
|
| 391 |
+
|
| 392 |
+
except Exception as e:
|
| 393 |
+
st.error(f"❌ Calculation failed: {str(e)}")
|
| 394 |
+
|
| 395 |
+
with col2:
|
| 396 |
+
st.markdown("### 📋 Emission Factors")
|
| 397 |
+
factors_df = calculator.get_emission_factors_table()
|
| 398 |
+
st.dataframe(factors_df, use_container_width=True)
|
| 399 |
+
|
| 400 |
+
st.markdown("### 🌱 Green Tips")
|
| 401 |
+
st.info("""
|
| 402 |
+
**Reduce Emissions:**
|
| 403 |
+
- Choose rail over road when possible
|
| 404 |
+
- Use container ships for long distances
|
| 405 |
+
- Optimize load capacity
|
| 406 |
+
- Consider multimodal transport
|
| 407 |
+
""")
|
| 408 |
+
|
| 409 |
+
elif page == "🗺️ Route Optimizer":
|
| 410 |
+
st.markdown("## 🗺️ Green Route Optimizer")
|
| 411 |
+
st.markdown("Find the most eco-friendly routes for your shipments")
|
| 412 |
+
|
| 413 |
+
with st.form("route_optimizer"):
|
| 414 |
+
col1, col2 = st.columns(2)
|
| 415 |
+
|
| 416 |
+
with col1:
|
| 417 |
+
origin = st.text_input("Origin", value="New York, NY", placeholder="Enter origin city")
|
| 418 |
+
destination = st.text_input("Destination", value="Los Angeles, CA", placeholder="Enter destination city")
|
| 419 |
+
|
| 420 |
+
with col2:
|
| 421 |
+
weight = st.number_input("Shipment Weight (tonnes)", min_value=0.01, value=5.0, step=0.1)
|
| 422 |
+
max_time_penalty = st.slider("Max Time Penalty (%)", 0, 50, 10)
|
| 423 |
+
|
| 424 |
+
optimize_btn = st.form_submit_button("🗺️ Find Green Routes", type="primary")
|
| 425 |
+
|
| 426 |
+
if optimize_btn and origin and destination:
|
| 427 |
+
with st.spinner("🔍 Finding optimal routes..."):
|
| 428 |
+
try:
|
| 429 |
+
# Get route recommendations
|
| 430 |
+
recommendations = optimizer.recommend_green_routes(origin, destination, weight)
|
| 431 |
+
|
| 432 |
+
if 'success' in recommendations and recommendations['success']:
|
| 433 |
+
st.success("✅ Route optimization complete!")
|
| 434 |
+
|
| 435 |
+
route_data = recommendations['recommendations']
|
| 436 |
+
|
| 437 |
+
# Display recommendations
|
| 438 |
+
st.markdown("### 🌱 Green Route Recommendations")
|
| 439 |
+
|
| 440 |
+
for i, route in enumerate(route_data):
|
| 441 |
+
with st.expander(f"Option {i+1}: {route['transport_mode'].replace('_', ' ').title()}", expanded=(i==0)):
|
| 442 |
+
col_a, col_b, col_c, col_d = st.columns(4)
|
| 443 |
+
|
| 444 |
+
with col_a:
|
| 445 |
+
st.metric("CO₂ Emissions", f"{route['co2_emissions_kg']:.1f} kg")
|
| 446 |
+
with col_b:
|
| 447 |
+
st.metric("Travel Time", f"{route['estimated_travel_time_hours']:.1f} hrs")
|
| 448 |
+
with col_c:
|
| 449 |
+
st.metric("Carbon Tax", f"${route['carbon_tax_cost_usd']:.2f}")
|
| 450 |
+
with col_d:
|
| 451 |
+
if route['emission_reduction_percent'] > 0:
|
| 452 |
+
st.metric("Emission Reduction", f"{route['emission_reduction_percent']:.1f}%", "vs worst option")
|
| 453 |
+
else:
|
| 454 |
+
st.metric("Emission Impact", "Baseline", "")
|
| 455 |
+
|
| 456 |
+
if i == 0:
|
| 457 |
+
st.markdown('<span class="eco-badge">🌱 RECOMMENDED</span>', unsafe_allow_html=True)
|
| 458 |
+
|
| 459 |
+
# Visualization
|
| 460 |
+
if len(route_data) > 1:
|
| 461 |
+
st.markdown("### 📊 Route Comparison")
|
| 462 |
+
|
| 463 |
+
df_viz = pd.DataFrame(route_data)
|
| 464 |
+
|
| 465 |
+
fig = make_subplots(
|
| 466 |
+
rows=1, cols=2,
|
| 467 |
+
subplot_titles=('CO₂ Emissions (kg)', 'Travel Time (hours)'),
|
| 468 |
+
specs=[[{"secondary_y": False}, {"secondary_y": False}]]
|
| 469 |
+
)
|
| 470 |
+
|
| 471 |
+
fig.add_trace(
|
| 472 |
+
go.Bar(
|
| 473 |
+
x=df_viz['transport_mode'],
|
| 474 |
+
y=df_viz['co2_emissions_kg'],
|
| 475 |
+
name='CO₂ Emissions',
|
| 476 |
+
marker_color='#2ECC71'
|
| 477 |
+
),
|
| 478 |
+
row=1, col=1
|
| 479 |
+
)
|
| 480 |
+
|
| 481 |
+
fig.add_trace(
|
| 482 |
+
go.Bar(
|
| 483 |
+
x=df_viz['transport_mode'],
|
| 484 |
+
y=df_viz['estimated_travel_time_hours'],
|
| 485 |
+
name='Travel Time',
|
| 486 |
+
marker_color='#3498DB'
|
| 487 |
+
),
|
| 488 |
+
row=1, col=2
|
| 489 |
+
)
|
| 490 |
+
|
| 491 |
+
fig.update_layout(height=400, showlegend=False)
|
| 492 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 493 |
+
|
| 494 |
+
else:
|
| 495 |
+
st.error(f"❌ Route optimization failed: {recommendations.get('error', 'Unknown error')}")
|
| 496 |
+
|
| 497 |
+
except Exception as e:
|
| 498 |
+
st.error(f"❌ Error: {str(e)}")
|
| 499 |
+
|
| 500 |
+
elif page == "📊 Scenario Analysis":
|
| 501 |
+
st.markdown("## 📊 Business Impact Simulation")
|
| 502 |
+
st.markdown("Analyze the potential impact of adopting green shipping practices")
|
| 503 |
+
|
| 504 |
+
with st.form("scenario_analysis"):
|
| 505 |
+
col1, col2 = st.columns(2)
|
| 506 |
+
|
| 507 |
+
with col1:
|
| 508 |
+
st.markdown("### 📦 Shipment Parameters")
|
| 509 |
+
total_shipments = st.number_input("Total Monthly Shipments", min_value=1, value=1000, step=50)
|
| 510 |
+
avg_distance = st.number_input("Average Distance (km)", min_value=1.0, value=800.0, step=50.0)
|
| 511 |
+
avg_weight = st.number_input("Average Weight (tonnes)", min_value=0.1, value=3.0, step=0.1)
|
| 512 |
+
|
| 513 |
+
with col2:
|
| 514 |
+
st.markdown("### ⚙️ Optimization Parameters")
|
| 515 |
+
optimization_percent = st.slider("% Shipments Using Green Routes", 0, 100, 50)
|
| 516 |
+
current_mode = st.selectbox("Current Transport Mode", [mode.value for mode in TransportMode], index=0)
|
| 517 |
+
carbon_tax_rate = st.number_input("Carbon Tax Rate ($/tonne CO₂)", min_value=0.0, value=50.0, step=5.0)
|
| 518 |
+
|
| 519 |
+
analyze_btn = st.form_submit_button("📊 Run Scenario Analysis", type="primary")
|
| 520 |
+
|
| 521 |
+
if analyze_btn:
|
| 522 |
+
with st.spinner("🔄 Running business impact simulation..."):
|
| 523 |
+
try:
|
| 524 |
+
# Current emissions - use same mapping as before
|
| 525 |
+
mode_mapping = {
|
| 526 |
+
'road_truck': TransportMode.ROAD_TRUCK,
|
| 527 |
+
'road_van': TransportMode.ROAD_VAN,
|
| 528 |
+
'rail': TransportMode.RAIL,
|
| 529 |
+
'air_cargo': TransportMode.AIR_CARGO,
|
| 530 |
+
'ship_container': TransportMode.SHIP_CONTAINER,
|
| 531 |
+
'ship_bulk': TransportMode.SHIP_BULK
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
+
if current_mode in mode_mapping:
|
| 535 |
+
current_mode_enum = mode_mapping[current_mode]
|
| 536 |
+
else:
|
| 537 |
+
current_mode_enum = TransportMode(current_mode)
|
| 538 |
+
|
| 539 |
+
current_emissions = calculator.calculate_emissions(avg_distance, avg_weight, current_mode_enum)
|
| 540 |
+
|
| 541 |
+
# Find best green alternative - calculate manually to avoid EmissionOptimizer import
|
| 542 |
+
available_modes = [TransportMode.ROAD_TRUCK, TransportMode.RAIL, TransportMode.SHIP_CONTAINER]
|
| 543 |
+
|
| 544 |
+
# Calculate emissions for each mode and find the greenest
|
| 545 |
+
mode_options = []
|
| 546 |
+
for mode in available_modes:
|
| 547 |
+
emissions = calculator.calculate_emissions(avg_distance, avg_weight, mode)
|
| 548 |
+
mode_options.append({
|
| 549 |
+
'mode': mode,
|
| 550 |
+
'co2_emissions_kg': emissions['co2_emissions_kg'],
|
| 551 |
+
'emission_factor': emissions['emission_factor']
|
| 552 |
+
})
|
| 553 |
+
|
| 554 |
+
# Sort by emissions (lowest first) to find greenest option
|
| 555 |
+
mode_options.sort(key=lambda x: x['co2_emissions_kg'])
|
| 556 |
+
green_option = mode_options[0] if mode_options else None
|
| 557 |
+
|
| 558 |
+
if not green_option:
|
| 559 |
+
st.error("❌ No green alternatives available")
|
| 560 |
+
st.stop()
|
| 561 |
+
|
| 562 |
+
# Calculate scenario impact
|
| 563 |
+
optimized_shipments = int(total_shipments * optimization_percent / 100)
|
| 564 |
+
regular_shipments = total_shipments - optimized_shipments
|
| 565 |
+
|
| 566 |
+
current_total = current_emissions['co2_emissions_kg'] * total_shipments
|
| 567 |
+
optimized_total = (
|
| 568 |
+
green_option['co2_emissions_kg'] * optimized_shipments +
|
| 569 |
+
current_emissions['co2_emissions_kg'] * regular_shipments
|
| 570 |
+
)
|
| 571 |
+
|
| 572 |
+
savings_kg = current_total - optimized_total
|
| 573 |
+
savings_percent = (savings_kg / current_total) * 100
|
| 574 |
+
carbon_tax_savings = (savings_kg / 1000) * carbon_tax_rate
|
| 575 |
+
|
| 576 |
+
st.success("✅ Scenario analysis complete!")
|
| 577 |
+
|
| 578 |
+
# Results
|
| 579 |
+
col1, col2, col3, col4 = st.columns(4)
|
| 580 |
+
|
| 581 |
+
with col1:
|
| 582 |
+
st.metric("Current Emissions", f"{current_total/1000:.1f} tonnes/month")
|
| 583 |
+
with col2:
|
| 584 |
+
st.metric("Optimized Emissions", f"{optimized_total/1000:.1f} tonnes/month")
|
| 585 |
+
with col3:
|
| 586 |
+
st.metric("CO₂ Savings", f"{savings_kg/1000:.1f} tonnes/month", f"{savings_percent:.1f}% reduction")
|
| 587 |
+
with col4:
|
| 588 |
+
st.metric("Carbon Tax Savings", f"${carbon_tax_savings:.0f}/month", f"${carbon_tax_savings*12:.0f}/year")
|
| 589 |
+
|
| 590 |
+
# Visualization
|
| 591 |
+
st.markdown("### 📈 Impact Visualization")
|
| 592 |
+
|
| 593 |
+
scenario_data = pd.DataFrame({
|
| 594 |
+
'Scenario': ['Current', 'Optimized'],
|
| 595 |
+
'CO₂ Emissions (tonnes)': [current_total/1000, optimized_total/1000],
|
| 596 |
+
'Carbon Tax Cost ($)': [
|
| 597 |
+
(current_total/1000) * carbon_tax_rate,
|
| 598 |
+
(optimized_total/1000) * carbon_tax_rate
|
| 599 |
+
]
|
| 600 |
+
})
|
| 601 |
+
|
| 602 |
+
fig = make_subplots(
|
| 603 |
+
rows=1, cols=2,
|
| 604 |
+
subplot_titles=('CO₂ Emissions', 'Carbon Tax Cost'),
|
| 605 |
+
specs=[[{"secondary_y": False}, {"secondary_y": False}]]
|
| 606 |
+
)
|
| 607 |
+
|
| 608 |
+
fig.add_trace(
|
| 609 |
+
go.Bar(
|
| 610 |
+
x=scenario_data['Scenario'],
|
| 611 |
+
y=scenario_data['CO₂ Emissions (tonnes)'],
|
| 612 |
+
name='CO₂ Emissions',
|
| 613 |
+
marker_color=['#E74C3C', '#2ECC71']
|
| 614 |
+
),
|
| 615 |
+
row=1, col=1
|
| 616 |
+
)
|
| 617 |
+
|
| 618 |
+
fig.add_trace(
|
| 619 |
+
go.Bar(
|
| 620 |
+
x=scenario_data['Scenario'],
|
| 621 |
+
y=scenario_data['Carbon Tax Cost ($)'],
|
| 622 |
+
name='Carbon Tax Cost',
|
| 623 |
+
marker_color=['#E74C3C', '#2ECC71']
|
| 624 |
+
),
|
| 625 |
+
row=1, col=2
|
| 626 |
+
)
|
| 627 |
+
|
| 628 |
+
fig.update_layout(height=400, showlegend=False)
|
| 629 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 630 |
+
|
| 631 |
+
# Business benefits
|
| 632 |
+
st.markdown("### 💼 Business Benefits")
|
| 633 |
+
|
| 634 |
+
benefits_col1, benefits_col2 = st.columns(2)
|
| 635 |
+
|
| 636 |
+
with benefits_col1:
|
| 637 |
+
st.markdown("""
|
| 638 |
+
**Environmental Impact:**
|
| 639 |
+
- ♻️ Reduced carbon footprint
|
| 640 |
+
- 🌱 Enhanced sustainability profile
|
| 641 |
+
- 📊 ESG score improvement
|
| 642 |
+
- 🏆 Industry leadership positioning
|
| 643 |
+
""")
|
| 644 |
+
|
| 645 |
+
with benefits_col2:
|
| 646 |
+
st.markdown(f"""
|
| 647 |
+
**Financial Benefits:**
|
| 648 |
+
- 💰 ${carbon_tax_savings*12:.0f} annual tax savings
|
| 649 |
+
- 📈 Potential green financing access
|
| 650 |
+
- 🎯 Regulatory compliance readiness
|
| 651 |
+
- 💡 Operational efficiency gains
|
| 652 |
+
""")
|
| 653 |
+
|
| 654 |
+
except Exception as e:
|
| 655 |
+
st.error(f"❌ Analysis failed: {str(e)}")
|
| 656 |
+
st.write(f"Debug info: {type(e).__name__}: {e}")
|
| 657 |
+
import traceback
|
| 658 |
+
st.code(traceback.format_exc())
|
| 659 |
+
|
| 660 |
+
elif page == "📈 Analytics":
|
| 661 |
+
st.markdown("## 📈 Advanced Analytics")
|
| 662 |
+
|
| 663 |
+
# Sample analytics data
|
| 664 |
+
st.markdown("### 🎯 Performance Metrics")
|
| 665 |
+
|
| 666 |
+
col1, col2, col3 = st.columns(3)
|
| 667 |
+
|
| 668 |
+
with col1:
|
| 669 |
+
st.markdown("""
|
| 670 |
+
<div class="metric-card">
|
| 671 |
+
<h4 style="color: #2ECC71; margin: 0;">Route Efficiency Score</h4>
|
| 672 |
+
<h2 style="margin: 0;">87/100</h2>
|
| 673 |
+
<p style="margin: 0; color: #7F8C8D;">Above industry average</p>
|
| 674 |
+
</div>
|
| 675 |
+
""", unsafe_allow_html=True)
|
| 676 |
+
|
| 677 |
+
with col2:
|
| 678 |
+
st.markdown("""
|
| 679 |
+
<div class="metric-card">
|
| 680 |
+
<h4 style="color: #2ECC71; margin: 0;">Green Route Adoption</h4>
|
| 681 |
+
<h2 style="margin: 0;">68%</h2>
|
| 682 |
+
<p style="margin: 0; color: #7F8C8D;">Target: 75%</p>
|
| 683 |
+
</div>
|
| 684 |
+
""", unsafe_allow_html=True)
|
| 685 |
+
|
| 686 |
+
with col3:
|
| 687 |
+
st.markdown("""
|
| 688 |
+
<div class="metric-card">
|
| 689 |
+
<h4 style="color: #2ECC71; margin: 0;">Emission Intensity</h4>
|
| 690 |
+
<h2 style="margin: 0;">0.045</h2>
|
| 691 |
+
<p style="margin: 0; color: #7F8C8D;">kg CO₂/tonne-km</p>
|
| 692 |
+
</div>
|
| 693 |
+
""", unsafe_allow_html=True)
|
| 694 |
+
|
| 695 |
+
# Regional analysis
|
| 696 |
+
st.markdown("### 🌍 Regional Emission Analysis")
|
| 697 |
+
|
| 698 |
+
regional_data = pd.DataFrame({
|
| 699 |
+
'Region': ['North America', 'Europe', 'Asia Pacific', 'Latin America'],
|
| 700 |
+
'Emissions (tonnes)': [45.2, 32.1, 28.7, 15.3],
|
| 701 |
+
'Shipments': [450, 320, 380, 180],
|
| 702 |
+
'Avg Distance (km)': [1200, 800, 950, 600]
|
| 703 |
+
})
|
| 704 |
+
|
| 705 |
+
fig = px.scatter(
|
| 706 |
+
regional_data,
|
| 707 |
+
x='Shipments',
|
| 708 |
+
y='Emissions (tonnes)',
|
| 709 |
+
size='Avg Distance (km)',
|
| 710 |
+
color='Region',
|
| 711 |
+
title="Regional Emission vs Shipment Volume"
|
| 712 |
+
)
|
| 713 |
+
fig.update_layout(height=500)
|
| 714 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 715 |
+
|
| 716 |
+
st.dataframe(regional_data, use_container_width=True)
|
| 717 |
+
|
| 718 |
+
|
| 719 |
+
# Footer
|
| 720 |
+
st.markdown("---")
|
| 721 |
+
st.markdown("## 👨💻 Developer Details")
|
| 722 |
+
st.markdown("""
|
| 723 |
+
<div style="text-align: center; color: #2C3E50; padding: 2rem; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
|
| 724 |
+
<div style="margin-bottom: 1rem;">
|
| 725 |
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" style="width: 60px; height: 60px;">
|
| 726 |
+
<defs>
|
| 727 |
+
<linearGradient id="zkGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
| 728 |
+
<stop offset="0%" style="stop-color:#2ECC71;stop-opacity:1" />
|
| 729 |
+
<stop offset="100%" style="stop-color:#27AE60;stop-opacity:1" />
|
| 730 |
+
</linearGradient>
|
| 731 |
+
</defs>
|
| 732 |
+
<g transform="translate(50, 50)">
|
| 733 |
+
<path d="M10 20 L70 20 L70 35 L35 75 L70 75 L70 90 L10 90 L10 75 L45 35 L10 35 Z"
|
| 734 |
+
fill="url(#zkGradient)"
|
| 735 |
+
stroke="#1E8449"
|
| 736 |
+
stroke-width="1"/>
|
| 737 |
+
<path d="M80 20 L95 20 L95 50 L110 20 L130 20 L110 55 L130 90 L110 90 L95 65 L95 90 L80 90 Z"
|
| 738 |
+
fill="url(#zkGradient)"
|
| 739 |
+
stroke="#1E8449"
|
| 740 |
+
stroke-width="1"/>
|
| 741 |
+
</g>
|
| 742 |
+
</svg>
|
| 743 |
+
</div>
|
| 744 |
+
<p style="font-size: 1.2rem; color: #2C3E50; margin-bottom: 0.5rem;"><strong>GreenPath</strong> - AI-Powered CO₂ Emission Reduction Platform</p>
|
| 745 |
+
<p style="font-size: 1.1rem; color: #34495E; margin-bottom: 1rem;">Designed and Developed by <strong>Sayed Mohd Zayeem Khateeb</strong></p>
|
| 746 |
+
<div style="margin: 1rem 0;">
|
| 747 |
+
<a href="https://github.com/zayeemskhateeb-cloud" target="_blank" style="margin: 0 10px; text-decoration: none; color: #2ECC71; font-weight: bold; font-size: 1rem;">🌐 GitHub</a> |
|
| 748 |
+
<a href="https://www.linkedin.com/in/zayeemkhateeb" target="_blank" style="margin: 0 10px; text-decoration: none; color: #2ECC71; font-weight: bold; font-size: 1rem;">💼 LinkedIn</a> |
|
| 749 |
+
<a href="mailto:zayeem.s.khateeb@gmail.com" style="margin: 0 10px; text-decoration: none; color: #2ECC71; font-weight: bold; font-size: 1rem;">📧 Email</a>
|
| 750 |
+
</div>
|
| 751 |
+
<p style="font-size: 1rem; color: #7F8C8D; margin-top: 1rem;">
|
| 752 |
+
Specialized in AI/ML, Data Analytics, and Sustainable Technology Solutions
|
| 753 |
+
</p>
|
| 754 |
+
</div>
|
| 755 |
+
""", unsafe_allow_html=True)
|
data_import.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Data Import Script for AI-Powered Shipment Route Optimization System
|
| 4 |
+
Created by: Zayeem Khateeb
|
| 5 |
+
|
| 6 |
+
This script helps you import your real data into the system.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import pandas as pd
|
| 10 |
+
import sys
|
| 11 |
+
import os
|
| 12 |
+
from datetime import datetime
|
| 13 |
+
|
| 14 |
+
# Add src directory to path
|
| 15 |
+
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
|
| 16 |
+
|
| 17 |
+
from config.database import DatabaseConfig
|
| 18 |
+
|
| 19 |
+
class DataImporter:
|
| 20 |
+
def __init__(self):
|
| 21 |
+
self.db = DatabaseConfig()
|
| 22 |
+
|
| 23 |
+
def import_from_csv(self, csv_file_path, table_name):
|
| 24 |
+
"""Import data from CSV file to database table"""
|
| 25 |
+
try:
|
| 26 |
+
# Read CSV file
|
| 27 |
+
df = pd.read_csv(csv_file_path)
|
| 28 |
+
print(f"📁 Loaded {len(df)} records from {csv_file_path}")
|
| 29 |
+
|
| 30 |
+
# Convert to database format
|
| 31 |
+
if table_name == 'shipments':
|
| 32 |
+
df = self._prepare_shipments_data(df)
|
| 33 |
+
elif table_name == 'weather_data':
|
| 34 |
+
df = self._prepare_weather_data(df)
|
| 35 |
+
elif table_name == 'traffic_data':
|
| 36 |
+
df = self._prepare_traffic_data(df)
|
| 37 |
+
|
| 38 |
+
# Insert into database
|
| 39 |
+
self._insert_dataframe(df, table_name)
|
| 40 |
+
print(f"✅ Successfully imported {len(df)} records to {table_name} table")
|
| 41 |
+
|
| 42 |
+
except Exception as e:
|
| 43 |
+
print(f"❌ Error importing data: {e}")
|
| 44 |
+
|
| 45 |
+
def _prepare_shipments_data(self, df):
|
| 46 |
+
"""Prepare shipments data for database insertion"""
|
| 47 |
+
# Ensure required columns exist
|
| 48 |
+
required_cols = ['tracking_number', 'origin_lat', 'origin_lng',
|
| 49 |
+
'destination_lat', 'destination_lng', 'scheduled_delivery']
|
| 50 |
+
|
| 51 |
+
for col in required_cols:
|
| 52 |
+
if col not in df.columns:
|
| 53 |
+
raise ValueError(f"Missing required column: {col}")
|
| 54 |
+
|
| 55 |
+
# Convert datetime columns
|
| 56 |
+
if 'scheduled_delivery' in df.columns:
|
| 57 |
+
df['scheduled_delivery'] = pd.to_datetime(df['scheduled_delivery'])
|
| 58 |
+
if 'actual_delivery' in df.columns:
|
| 59 |
+
df['actual_delivery'] = pd.to_datetime(df['actual_delivery'])
|
| 60 |
+
|
| 61 |
+
# Add created_at if not present
|
| 62 |
+
if 'created_at' not in df.columns:
|
| 63 |
+
df['created_at'] = datetime.now()
|
| 64 |
+
|
| 65 |
+
# Fill missing values
|
| 66 |
+
df['status'] = df.get('status', 'pending')
|
| 67 |
+
df['delay_minutes'] = df.get('delay_minutes', 0)
|
| 68 |
+
|
| 69 |
+
return df
|
| 70 |
+
|
| 71 |
+
def _prepare_weather_data(self, df):
|
| 72 |
+
"""Prepare weather data for database insertion"""
|
| 73 |
+
if 'timestamp' in df.columns:
|
| 74 |
+
df['timestamp'] = pd.to_datetime(df['timestamp'])
|
| 75 |
+
return df
|
| 76 |
+
|
| 77 |
+
def _prepare_traffic_data(self, df):
|
| 78 |
+
"""Prepare traffic data for database insertion"""
|
| 79 |
+
if 'timestamp' in df.columns:
|
| 80 |
+
df['timestamp'] = pd.to_datetime(df['timestamp'])
|
| 81 |
+
return df
|
| 82 |
+
|
| 83 |
+
def _insert_dataframe(self, df, table_name):
|
| 84 |
+
"""Insert DataFrame into database table"""
|
| 85 |
+
# This would use SQLAlchemy or pandas to_sql in production
|
| 86 |
+
# For now, we'll show the structure
|
| 87 |
+
print(f"📊 Data structure for {table_name}:")
|
| 88 |
+
print(df.head())
|
| 89 |
+
print(f"Columns: {list(df.columns)}")
|
| 90 |
+
|
| 91 |
+
def import_from_excel(self, excel_file_path, sheet_name='Sheet1', table_name='shipments'):
|
| 92 |
+
"""Import data from Excel file"""
|
| 93 |
+
try:
|
| 94 |
+
df = pd.read_excel(excel_file_path, sheet_name=sheet_name)
|
| 95 |
+
print(f"📁 Loaded {len(df)} records from {excel_file_path}")
|
| 96 |
+
|
| 97 |
+
# Convert to CSV temporarily and use CSV import
|
| 98 |
+
temp_csv = f"temp_{table_name}.csv"
|
| 99 |
+
df.to_csv(temp_csv, index=False)
|
| 100 |
+
self.import_from_csv(temp_csv, table_name)
|
| 101 |
+
|
| 102 |
+
# Clean up temp file
|
| 103 |
+
os.remove(temp_csv)
|
| 104 |
+
|
| 105 |
+
except Exception as e:
|
| 106 |
+
print(f"❌ Error importing Excel data: {e}")
|
| 107 |
+
|
| 108 |
+
def validate_data_format(self, csv_file_path, expected_format='shipments'):
|
| 109 |
+
"""Validate that your data has the correct format"""
|
| 110 |
+
try:
|
| 111 |
+
df = pd.read_csv(csv_file_path)
|
| 112 |
+
|
| 113 |
+
if expected_format == 'shipments':
|
| 114 |
+
required_cols = ['tracking_number', 'origin_lat', 'origin_lng',
|
| 115 |
+
'destination_lat', 'destination_lng']
|
| 116 |
+
optional_cols = ['origin_address', 'destination_address',
|
| 117 |
+
'scheduled_delivery', 'actual_delivery', 'status', 'delay_minutes']
|
| 118 |
+
|
| 119 |
+
elif expected_format == 'weather':
|
| 120 |
+
required_cols = ['location_lat', 'location_lng', 'timestamp', 'temperature']
|
| 121 |
+
optional_cols = ['humidity', 'wind_speed', 'precipitation', 'weather_condition']
|
| 122 |
+
|
| 123 |
+
elif expected_format == 'traffic':
|
| 124 |
+
required_cols = ['route_start_lat', 'route_start_lng', 'route_end_lat',
|
| 125 |
+
'route_end_lng', 'timestamp']
|
| 126 |
+
optional_cols = ['travel_time_minutes', 'distance_km', 'traffic_level']
|
| 127 |
+
|
| 128 |
+
# Check required columns
|
| 129 |
+
missing_cols = [col for col in required_cols if col not in df.columns]
|
| 130 |
+
if missing_cols:
|
| 131 |
+
print(f"❌ Missing required columns: {missing_cols}")
|
| 132 |
+
return False
|
| 133 |
+
|
| 134 |
+
# Show available columns
|
| 135 |
+
print(f"✅ Data validation passed for {expected_format} format")
|
| 136 |
+
print(f"📊 Found columns: {list(df.columns)}")
|
| 137 |
+
print(f"📈 Data shape: {df.shape}")
|
| 138 |
+
print(f"🔍 Sample data:")
|
| 139 |
+
print(df.head(3))
|
| 140 |
+
|
| 141 |
+
return True
|
| 142 |
+
|
| 143 |
+
except Exception as e:
|
| 144 |
+
print(f"❌ Error validating data: {e}")
|
| 145 |
+
return False
|
| 146 |
+
|
| 147 |
+
def main():
|
| 148 |
+
"""Main function to demonstrate data import"""
|
| 149 |
+
importer = DataImporter()
|
| 150 |
+
|
| 151 |
+
print("=" * 60)
|
| 152 |
+
print("🚛 DATA IMPORT TOOL - AI Shipment Route Optimization")
|
| 153 |
+
print("Created by: Zayeem Khateeb")
|
| 154 |
+
print("=" * 60)
|
| 155 |
+
print()
|
| 156 |
+
|
| 157 |
+
# Example usage
|
| 158 |
+
print("📋 USAGE EXAMPLES:")
|
| 159 |
+
print()
|
| 160 |
+
print("1. Validate your data format:")
|
| 161 |
+
print(" python data_import.py validate shipments.csv")
|
| 162 |
+
print()
|
| 163 |
+
print("2. Import shipments from CSV:")
|
| 164 |
+
print(" python data_import.py import shipments.csv shipments")
|
| 165 |
+
print()
|
| 166 |
+
print("3. Import weather data:")
|
| 167 |
+
print(" python data_import.py import weather_data.csv weather_data")
|
| 168 |
+
print()
|
| 169 |
+
print("4. Import from Excel:")
|
| 170 |
+
print(" python data_import.py excel shipments.xlsx Sheet1 shipments")
|
| 171 |
+
print()
|
| 172 |
+
|
| 173 |
+
# Handle command line arguments
|
| 174 |
+
if len(sys.argv) > 1:
|
| 175 |
+
command = sys.argv[1]
|
| 176 |
+
|
| 177 |
+
if command == 'validate' and len(sys.argv) >= 3:
|
| 178 |
+
file_path = sys.argv[2]
|
| 179 |
+
data_type = sys.argv[3] if len(sys.argv) > 3 else 'shipments'
|
| 180 |
+
importer.validate_data_format(file_path, data_type)
|
| 181 |
+
|
| 182 |
+
elif command == 'import' and len(sys.argv) >= 4:
|
| 183 |
+
file_path = sys.argv[2]
|
| 184 |
+
table_name = sys.argv[3]
|
| 185 |
+
importer.import_from_csv(file_path, table_name)
|
| 186 |
+
|
| 187 |
+
elif command == 'excel' and len(sys.argv) >= 5:
|
| 188 |
+
file_path = sys.argv[2]
|
| 189 |
+
sheet_name = sys.argv[3]
|
| 190 |
+
table_name = sys.argv[4]
|
| 191 |
+
importer.import_from_excel(file_path, sheet_name, table_name)
|
| 192 |
+
|
| 193 |
+
else:
|
| 194 |
+
print("💡 QUICK START:")
|
| 195 |
+
print("1. Prepare your data in CSV format (see DATA_INTEGRATION_GUIDE.md)")
|
| 196 |
+
print("2. Run: python data_import.py validate your_file.csv")
|
| 197 |
+
print("3. Run: python data_import.py import your_file.csv shipments")
|
| 198 |
+
|
| 199 |
+
if __name__ == "__main__":
|
| 200 |
+
main()
|
demo.py
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
AI-Powered Shipment Route Optimization & Delay Prediction System
|
| 4 |
+
Simplified demonstration without external dependencies
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import json
|
| 8 |
+
import random
|
| 9 |
+
import math
|
| 10 |
+
from datetime import datetime, timedelta
|
| 11 |
+
|
| 12 |
+
def generate_sample_shipments(n=100):
|
| 13 |
+
"""Generate sample shipment data for demonstration"""
|
| 14 |
+
cities = [
|
| 15 |
+
("New York", 40.7128, -74.0060),
|
| 16 |
+
("Los Angeles", 34.0522, -118.2437),
|
| 17 |
+
("Chicago", 41.8781, -87.6298),
|
| 18 |
+
("Houston", 29.7604, -95.3698),
|
| 19 |
+
("Phoenix", 33.4484, -112.0740),
|
| 20 |
+
("Philadelphia", 39.9526, -75.1652),
|
| 21 |
+
("San Antonio", 29.4241, -98.4936),
|
| 22 |
+
("San Diego", 32.7157, -117.1611),
|
| 23 |
+
("Dallas", 32.7767, -96.7970),
|
| 24 |
+
("San Jose", 37.3382, -121.8863)
|
| 25 |
+
]
|
| 26 |
+
|
| 27 |
+
shipments = []
|
| 28 |
+
for i in range(n):
|
| 29 |
+
origin = random.choice(cities)
|
| 30 |
+
destination = random.choice([c for c in cities if c != origin])
|
| 31 |
+
|
| 32 |
+
# Calculate distance
|
| 33 |
+
distance = calculate_distance(origin[1], origin[2], destination[1], destination[2])
|
| 34 |
+
|
| 35 |
+
# Generate realistic delivery time
|
| 36 |
+
base_time = distance / 60 # Assume 60 mph average
|
| 37 |
+
scheduled_delivery = datetime.now() + timedelta(hours=base_time + random.uniform(2, 24))
|
| 38 |
+
|
| 39 |
+
# Generate delay probability based on distance and random factors
|
| 40 |
+
delay_prob = min(0.9, 0.1 + (distance / 3000) + random.uniform(0, 0.3))
|
| 41 |
+
is_delayed = random.random() < delay_prob
|
| 42 |
+
delay_minutes = random.uniform(15, 120) if is_delayed else 0
|
| 43 |
+
|
| 44 |
+
shipments.append({
|
| 45 |
+
'tracking_number': f'TRK{i+1:06d}',
|
| 46 |
+
'origin': origin[0],
|
| 47 |
+
'origin_lat': origin[1],
|
| 48 |
+
'origin_lng': origin[2],
|
| 49 |
+
'destination': destination[0],
|
| 50 |
+
'destination_lat': destination[1],
|
| 51 |
+
'destination_lng': destination[2],
|
| 52 |
+
'distance_km': round(distance, 1),
|
| 53 |
+
'scheduled_delivery': scheduled_delivery.strftime('%Y-%m-%d %H:%M'),
|
| 54 |
+
'delay_probability': round(delay_prob, 3),
|
| 55 |
+
'delay_minutes': round(delay_minutes, 1),
|
| 56 |
+
'is_delayed': is_delayed,
|
| 57 |
+
'status': 'in_transit' if random.random() < 0.7 else 'pending'
|
| 58 |
+
})
|
| 59 |
+
|
| 60 |
+
return shipments
|
| 61 |
+
|
| 62 |
+
def calculate_distance(lat1, lng1, lat2, lng2):
|
| 63 |
+
"""Calculate distance using Haversine formula"""
|
| 64 |
+
R = 6371 # Earth's radius in km
|
| 65 |
+
|
| 66 |
+
lat1_rad = math.radians(lat1)
|
| 67 |
+
lng1_rad = math.radians(lng1)
|
| 68 |
+
lat2_rad = math.radians(lat2)
|
| 69 |
+
lng2_rad = math.radians(lng2)
|
| 70 |
+
|
| 71 |
+
dlat = lat2_rad - lat1_rad
|
| 72 |
+
dlng = lng2_rad - lng1_rad
|
| 73 |
+
|
| 74 |
+
a = (math.sin(dlat/2)**2 +
|
| 75 |
+
math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlng/2)**2)
|
| 76 |
+
c = 2 * math.asin(math.sqrt(a))
|
| 77 |
+
|
| 78 |
+
return R * c
|
| 79 |
+
|
| 80 |
+
def simulate_ml_model(shipments):
|
| 81 |
+
"""Simulate machine learning model predictions"""
|
| 82 |
+
high_risk = []
|
| 83 |
+
medium_risk = []
|
| 84 |
+
low_risk = []
|
| 85 |
+
|
| 86 |
+
for shipment in shipments:
|
| 87 |
+
prob = shipment['delay_probability']
|
| 88 |
+
if prob >= 0.7:
|
| 89 |
+
high_risk.append(shipment)
|
| 90 |
+
elif prob >= 0.4:
|
| 91 |
+
medium_risk.append(shipment)
|
| 92 |
+
else:
|
| 93 |
+
low_risk.append(shipment)
|
| 94 |
+
|
| 95 |
+
# Simulate model accuracy
|
| 96 |
+
correct_predictions = 0
|
| 97 |
+
total_predictions = len(shipments)
|
| 98 |
+
|
| 99 |
+
for shipment in shipments:
|
| 100 |
+
predicted_delay = shipment['delay_probability'] > 0.5
|
| 101 |
+
actual_delay = shipment['is_delayed']
|
| 102 |
+
if predicted_delay == actual_delay:
|
| 103 |
+
correct_predictions += 1
|
| 104 |
+
|
| 105 |
+
accuracy = correct_predictions / total_predictions
|
| 106 |
+
|
| 107 |
+
return {
|
| 108 |
+
'accuracy': accuracy,
|
| 109 |
+
'high_risk_count': len(high_risk),
|
| 110 |
+
'medium_risk_count': len(medium_risk),
|
| 111 |
+
'low_risk_count': len(low_risk),
|
| 112 |
+
'high_risk_shipments': high_risk[:5] # Show top 5
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
def simulate_route_optimization():
|
| 116 |
+
"""Simulate route optimization algorithms"""
|
| 117 |
+
routes = [
|
| 118 |
+
{
|
| 119 |
+
'route_id': 1,
|
| 120 |
+
'path': ['New York', 'Philadelphia', 'Chicago', 'Denver', 'Los Angeles'],
|
| 121 |
+
'total_distance': 2789.5,
|
| 122 |
+
'estimated_time': 46.5,
|
| 123 |
+
'algorithm': 'Dijkstra',
|
| 124 |
+
'efficiency_score': 87.3
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
'route_id': 2,
|
| 128 |
+
'path': ['New York', 'Pittsburgh', 'Chicago', 'Kansas City', 'Los Angeles'],
|
| 129 |
+
'total_distance': 2834.2,
|
| 130 |
+
'estimated_time': 47.2,
|
| 131 |
+
'algorithm': 'A*',
|
| 132 |
+
'efficiency_score': 85.1
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
'route_id': 3,
|
| 136 |
+
'path': ['New York', 'Cleveland', 'Chicago', 'Omaha', 'Denver', 'Los Angeles'],
|
| 137 |
+
'total_distance': 2901.8,
|
| 138 |
+
'estimated_time': 48.4,
|
| 139 |
+
'algorithm': 'A* (Weather-Adjusted)',
|
| 140 |
+
'efficiency_score': 83.7
|
| 141 |
+
}
|
| 142 |
+
]
|
| 143 |
+
|
| 144 |
+
return routes
|
| 145 |
+
|
| 146 |
+
def generate_alerts(shipments):
|
| 147 |
+
"""Generate monitoring alerts"""
|
| 148 |
+
alerts = []
|
| 149 |
+
|
| 150 |
+
for shipment in shipments:
|
| 151 |
+
if shipment['delay_probability'] >= 0.8:
|
| 152 |
+
alert = {
|
| 153 |
+
'type': 'HIGH_DELAY_RISK',
|
| 154 |
+
'severity': 'HIGH',
|
| 155 |
+
'tracking_number': shipment['tracking_number'],
|
| 156 |
+
}
|
| 157 |
+
alert['message'] = f"High delay risk ({shipment['delay_probability']:.1%}) for {shipment['origin']} -> {shipment['destination']}"
|
| 158 |
+
alert['recommendations'] = [
|
| 159 |
+
'Consider alternative routing',
|
| 160 |
+
'Notify customer proactively',
|
| 161 |
+
'Monitor weather conditions'
|
| 162 |
+
]
|
| 163 |
+
alerts.append(alert)
|
| 164 |
+
|
| 165 |
+
# Simulate weather alerts
|
| 166 |
+
if random.random() < 0.1: # 10% chance of weather alert
|
| 167 |
+
alerts.append({
|
| 168 |
+
'type': 'WEATHER_WARNING',
|
| 169 |
+
'severity': 'MEDIUM',
|
| 170 |
+
'tracking_number': shipment['tracking_number'],
|
| 171 |
+
'message': f"Severe weather detected on route to {shipment['destination']}",
|
| 172 |
+
'recommendations': [
|
| 173 |
+
'Monitor weather updates',
|
| 174 |
+
'Allow extra travel time'
|
| 175 |
+
]
|
| 176 |
+
})
|
| 177 |
+
|
| 178 |
+
return alerts
|
| 179 |
+
|
| 180 |
+
def main():
|
| 181 |
+
"""Main demonstration function"""
|
| 182 |
+
print("=" * 70)
|
| 183 |
+
print("AI-POWERED SHIPMENT ROUTE OPTIMIZATION & DELAY PREDICTION")
|
| 184 |
+
print("=" * 70)
|
| 185 |
+
print()
|
| 186 |
+
|
| 187 |
+
# Step 1: Generate sample data
|
| 188 |
+
print("STEP 1: Data Generation & Processing")
|
| 189 |
+
print("-" * 50)
|
| 190 |
+
shipments = generate_sample_shipments(500)
|
| 191 |
+
print(f"Generated {len(shipments)} sample shipments")
|
| 192 |
+
|
| 193 |
+
# Calculate summary statistics
|
| 194 |
+
total_distance = sum(s['distance_km'] for s in shipments)
|
| 195 |
+
avg_distance = total_distance / len(shipments)
|
| 196 |
+
delayed_shipments = sum(1 for s in shipments if s['is_delayed'])
|
| 197 |
+
on_time_rate = (len(shipments) - delayed_shipments) / len(shipments) * 100
|
| 198 |
+
|
| 199 |
+
print(f" • Total distance: {total_distance:,.0f} km")
|
| 200 |
+
print(f" • Average distance: {avg_distance:.1f} km")
|
| 201 |
+
print(f" • On-time rate: {on_time_rate:.1f}%")
|
| 202 |
+
|
| 203 |
+
# Step 2: Machine Learning Predictions
|
| 204 |
+
print(f"\nSTEP 2: Machine Learning Delay Prediction")
|
| 205 |
+
print("-" * 50)
|
| 206 |
+
ml_results = simulate_ml_model(shipments)
|
| 207 |
+
print(f"Model trained with {ml_results['accuracy']:.1%} accuracy")
|
| 208 |
+
print(f" • High risk shipments: {ml_results['high_risk_count']}")
|
| 209 |
+
print(f" • Medium risk shipments: {ml_results['medium_risk_count']}")
|
| 210 |
+
print(f" • Low risk shipments: {ml_results['low_risk_count']}")
|
| 211 |
+
|
| 212 |
+
print(f"\nTop High-Risk Shipments:")
|
| 213 |
+
for shipment in ml_results['high_risk_shipments']:
|
| 214 |
+
print(f" • {shipment['tracking_number']}: {shipment['origin']} -> {shipment['destination']} "
|
| 215 |
+
f"({shipment['delay_probability']:.1%} risk)")
|
| 216 |
+
|
| 217 |
+
# Step 3: Route Optimization
|
| 218 |
+
print(f"\nSTEP 3: Route Optimization")
|
| 219 |
+
print("-" * 50)
|
| 220 |
+
routes = simulate_route_optimization()
|
| 221 |
+
print(f"Found {len(routes)} optimized routes for NY -> LA:")
|
| 222 |
+
|
| 223 |
+
for route in routes:
|
| 224 |
+
print(f" Route {route['route_id']} ({route['algorithm']}):")
|
| 225 |
+
print(f" Path: {' -> '.join(route['path'])}")
|
| 226 |
+
print(f" Distance: {route['total_distance']:.1f} km")
|
| 227 |
+
print(f" Time: {route['estimated_time']:.1f} hours")
|
| 228 |
+
print(f" Efficiency: {route['efficiency_score']:.1f}%")
|
| 229 |
+
print()
|
| 230 |
+
|
| 231 |
+
# Step 4: Real-time Monitoring
|
| 232 |
+
print(f"STEP 4: Real-time Monitoring & Alerts")
|
| 233 |
+
print("-" * 50)
|
| 234 |
+
alerts = generate_alerts(shipments)
|
| 235 |
+
print(f"Generated {len(alerts)} active alerts")
|
| 236 |
+
|
| 237 |
+
high_severity_alerts = [a for a in alerts if a['severity'] == 'HIGH']
|
| 238 |
+
medium_severity_alerts = [a for a in alerts if a['severity'] == 'MEDIUM']
|
| 239 |
+
|
| 240 |
+
print(f" • High severity: {len(high_severity_alerts)}")
|
| 241 |
+
print(f" • Medium severity: {len(medium_severity_alerts)}")
|
| 242 |
+
|
| 243 |
+
if high_severity_alerts:
|
| 244 |
+
print(f"\nCritical Alerts:")
|
| 245 |
+
for alert in high_severity_alerts[:3]: # Show top 3
|
| 246 |
+
print(f" • {alert['tracking_number']}: {alert['message']}")
|
| 247 |
+
|
| 248 |
+
# Step 5: Business Impact Analysis
|
| 249 |
+
print(f"\nSTEP 5: Business Impact Analysis")
|
| 250 |
+
print("-" * 50)
|
| 251 |
+
|
| 252 |
+
# Calculate potential improvements
|
| 253 |
+
baseline_delays = sum(s['delay_minutes'] for s in shipments if s['is_delayed'])
|
| 254 |
+
potential_reduction = baseline_delays * 0.15 # 15% improvement
|
| 255 |
+
|
| 256 |
+
print(f"Projected Business Benefits:")
|
| 257 |
+
print(f" • Current total delay time: {baseline_delays:,.0f} minutes")
|
| 258 |
+
print(f" • Potential reduction: {potential_reduction:,.0f} minutes (15%)")
|
| 259 |
+
print(f" • Improved customer satisfaction through proactive alerts")
|
| 260 |
+
print(f" • Real-time visibility into {len(shipments)} shipments")
|
| 261 |
+
print(f" • Data-driven route optimization saving fuel costs")
|
| 262 |
+
|
| 263 |
+
# Step 6: System Summary
|
| 264 |
+
print(f"\nSTEP 6: System Performance Summary")
|
| 265 |
+
print("-" * 50)
|
| 266 |
+
print(f"Key Achievements:")
|
| 267 |
+
print(f" • ML Model Accuracy: {ml_results['accuracy']:.1%}")
|
| 268 |
+
print(f" • Route Optimization: {len(routes)} alternative paths found")
|
| 269 |
+
print(f" • Active Monitoring: {len(alerts)} alerts generated")
|
| 270 |
+
print(f" • Risk Assessment: {ml_results['high_risk_count']} high-risk shipments identified")
|
| 271 |
+
|
| 272 |
+
print(f"\nSystem Status: OPERATIONAL")
|
| 273 |
+
print(f" Dashboard: Ready for deployment")
|
| 274 |
+
print(f" API Endpoints: Configured")
|
| 275 |
+
print(f" Monitoring: Active")
|
| 276 |
+
print(f" Alerts: Enabled")
|
| 277 |
+
|
| 278 |
+
# Save results to JSON for dashboard
|
| 279 |
+
results = {
|
| 280 |
+
'timestamp': datetime.now().isoformat(),
|
| 281 |
+
'total_shipments': len(shipments),
|
| 282 |
+
'model_accuracy': ml_results['accuracy'],
|
| 283 |
+
'on_time_rate': on_time_rate / 100,
|
| 284 |
+
'total_alerts': len(alerts),
|
| 285 |
+
'high_risk_shipments': ml_results['high_risk_count'],
|
| 286 |
+
'routes_optimized': len(routes),
|
| 287 |
+
'sample_shipments': shipments[:10], # First 10 for display
|
| 288 |
+
'sample_routes': routes,
|
| 289 |
+
'sample_alerts': alerts[:5] # First 5 alerts
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
with open('demo_results.json', 'w') as f:
|
| 293 |
+
json.dump(results, f, indent=2)
|
| 294 |
+
|
| 295 |
+
print(f"\nResults saved to: demo_results.json")
|
| 296 |
+
print(f"To start the web dashboard: python src/dashboard/app.py")
|
| 297 |
+
|
| 298 |
+
return results
|
| 299 |
+
|
| 300 |
+
if __name__ == "__main__":
|
| 301 |
+
results = main()
|
| 302 |
+
print(f"\n{'='*70}")
|
| 303 |
+
print(f"Demo completed successfully! System ready for production deployment.")
|
| 304 |
+
print(f"{'='*70}")
|
demo_results.json
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"timestamp": "2025-09-10T23:56:33.497674",
|
| 3 |
+
"total_shipments": 500,
|
| 4 |
+
"model_accuracy": 0.822,
|
| 5 |
+
"on_time_rate": 0.254,
|
| 6 |
+
"total_alerts": 364,
|
| 7 |
+
"high_risk_shipments": 341,
|
| 8 |
+
"routes_optimized": 3,
|
| 9 |
+
"sample_shipments": [
|
| 10 |
+
{
|
| 11 |
+
"tracking_number": "TRK000001",
|
| 12 |
+
"origin": "Houston",
|
| 13 |
+
"origin_lat": 29.7604,
|
| 14 |
+
"origin_lng": -95.3698,
|
| 15 |
+
"destination": "Los Angeles",
|
| 16 |
+
"destination_lat": 34.0522,
|
| 17 |
+
"destination_lng": -118.2437,
|
| 18 |
+
"distance_km": 2206.3,
|
| 19 |
+
"scheduled_delivery": "2025-09-12 16:03",
|
| 20 |
+
"delay_probability": 0.9,
|
| 21 |
+
"delay_minutes": 98.9,
|
| 22 |
+
"is_delayed": true,
|
| 23 |
+
"status": "in_transit"
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
"tracking_number": "TRK000002",
|
| 27 |
+
"origin": "Dallas",
|
| 28 |
+
"origin_lat": 32.7767,
|
| 29 |
+
"origin_lng": -96.797,
|
| 30 |
+
"destination": "San Diego",
|
| 31 |
+
"destination_lat": 32.7157,
|
| 32 |
+
"destination_lng": -117.1611,
|
| 33 |
+
"distance_km": 1901.6,
|
| 34 |
+
"scheduled_delivery": "2025-09-12 12:13",
|
| 35 |
+
"delay_probability": 0.9,
|
| 36 |
+
"delay_minutes": 96.8,
|
| 37 |
+
"is_delayed": true,
|
| 38 |
+
"status": "in_transit"
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"tracking_number": "TRK000003",
|
| 42 |
+
"origin": "Dallas",
|
| 43 |
+
"origin_lat": 32.7767,
|
| 44 |
+
"origin_lng": -96.797,
|
| 45 |
+
"destination": "Chicago",
|
| 46 |
+
"destination_lat": 41.8781,
|
| 47 |
+
"destination_lng": -87.6298,
|
| 48 |
+
"distance_km": 1295.0,
|
| 49 |
+
"scheduled_delivery": "2025-09-12 06:59",
|
| 50 |
+
"delay_probability": 0.825,
|
| 51 |
+
"delay_minutes": 15.6,
|
| 52 |
+
"is_delayed": true,
|
| 53 |
+
"status": "pending"
|
| 54 |
+
},
|
| 55 |
+
{
|
| 56 |
+
"tracking_number": "TRK000004",
|
| 57 |
+
"origin": "San Jose",
|
| 58 |
+
"origin_lat": 37.3382,
|
| 59 |
+
"origin_lng": -121.8863,
|
| 60 |
+
"destination": "Philadelphia",
|
| 61 |
+
"destination_lat": 39.9526,
|
| 62 |
+
"destination_lng": -75.1652,
|
| 63 |
+
"distance_km": 4021.5,
|
| 64 |
+
"scheduled_delivery": "2025-09-14 16:06",
|
| 65 |
+
"delay_probability": 0.9,
|
| 66 |
+
"delay_minutes": 0,
|
| 67 |
+
"is_delayed": false,
|
| 68 |
+
"status": "pending"
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"tracking_number": "TRK000005",
|
| 72 |
+
"origin": "Chicago",
|
| 73 |
+
"origin_lat": 41.8781,
|
| 74 |
+
"origin_lng": -87.6298,
|
| 75 |
+
"destination": "New York",
|
| 76 |
+
"destination_lat": 40.7128,
|
| 77 |
+
"destination_lng": -74.006,
|
| 78 |
+
"distance_km": 1144.3,
|
| 79 |
+
"scheduled_delivery": "2025-09-12 01:45",
|
| 80 |
+
"delay_probability": 0.704,
|
| 81 |
+
"delay_minutes": 57.2,
|
| 82 |
+
"is_delayed": true,
|
| 83 |
+
"status": "pending"
|
| 84 |
+
},
|
| 85 |
+
{
|
| 86 |
+
"tracking_number": "TRK000006",
|
| 87 |
+
"origin": "Philadelphia",
|
| 88 |
+
"origin_lat": 39.9526,
|
| 89 |
+
"origin_lng": -75.1652,
|
| 90 |
+
"destination": "Phoenix",
|
| 91 |
+
"destination_lat": 33.4484,
|
| 92 |
+
"destination_lng": -112.074,
|
| 93 |
+
"distance_km": 3344.1,
|
| 94 |
+
"scheduled_delivery": "2025-09-13 12:37",
|
| 95 |
+
"delay_probability": 0.9,
|
| 96 |
+
"delay_minutes": 54.4,
|
| 97 |
+
"is_delayed": true,
|
| 98 |
+
"status": "in_transit"
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"tracking_number": "TRK000007",
|
| 102 |
+
"origin": "Houston",
|
| 103 |
+
"origin_lat": 29.7604,
|
| 104 |
+
"origin_lng": -95.3698,
|
| 105 |
+
"destination": "San Antonio",
|
| 106 |
+
"destination_lat": 29.4241,
|
| 107 |
+
"destination_lng": -98.4936,
|
| 108 |
+
"distance_km": 304.3,
|
| 109 |
+
"scheduled_delivery": "2025-09-11 16:23",
|
| 110 |
+
"delay_probability": 0.464,
|
| 111 |
+
"delay_minutes": 0,
|
| 112 |
+
"is_delayed": false,
|
| 113 |
+
"status": "in_transit"
|
| 114 |
+
},
|
| 115 |
+
{
|
| 116 |
+
"tracking_number": "TRK000008",
|
| 117 |
+
"origin": "Dallas",
|
| 118 |
+
"origin_lat": 32.7767,
|
| 119 |
+
"origin_lng": -96.797,
|
| 120 |
+
"destination": "San Antonio",
|
| 121 |
+
"destination_lat": 29.4241,
|
| 122 |
+
"destination_lng": -98.4936,
|
| 123 |
+
"distance_km": 406.3,
|
| 124 |
+
"scheduled_delivery": "2025-09-11 18:45",
|
| 125 |
+
"delay_probability": 0.337,
|
| 126 |
+
"delay_minutes": 0,
|
| 127 |
+
"is_delayed": false,
|
| 128 |
+
"status": "pending"
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"tracking_number": "TRK000009",
|
| 132 |
+
"origin": "Los Angeles",
|
| 133 |
+
"origin_lat": 34.0522,
|
| 134 |
+
"origin_lng": -118.2437,
|
| 135 |
+
"destination": "Phoenix",
|
| 136 |
+
"destination_lat": 33.4484,
|
| 137 |
+
"destination_lng": -112.074,
|
| 138 |
+
"distance_km": 574.3,
|
| 139 |
+
"scheduled_delivery": "2025-09-12 04:35",
|
| 140 |
+
"delay_probability": 0.333,
|
| 141 |
+
"delay_minutes": 116.4,
|
| 142 |
+
"is_delayed": true,
|
| 143 |
+
"status": "in_transit"
|
| 144 |
+
},
|
| 145 |
+
{
|
| 146 |
+
"tracking_number": "TRK000010",
|
| 147 |
+
"origin": "San Antonio",
|
| 148 |
+
"origin_lat": 29.4241,
|
| 149 |
+
"origin_lng": -98.4936,
|
| 150 |
+
"destination": "Houston",
|
| 151 |
+
"destination_lat": 29.7604,
|
| 152 |
+
"destination_lng": -95.3698,
|
| 153 |
+
"distance_km": 304.3,
|
| 154 |
+
"scheduled_delivery": "2025-09-11 18:42",
|
| 155 |
+
"delay_probability": 0.292,
|
| 156 |
+
"delay_minutes": 0,
|
| 157 |
+
"is_delayed": false,
|
| 158 |
+
"status": "in_transit"
|
| 159 |
+
}
|
| 160 |
+
],
|
| 161 |
+
"sample_routes": [
|
| 162 |
+
{
|
| 163 |
+
"route_id": 1,
|
| 164 |
+
"path": [
|
| 165 |
+
"New York",
|
| 166 |
+
"Philadelphia",
|
| 167 |
+
"Chicago",
|
| 168 |
+
"Denver",
|
| 169 |
+
"Los Angeles"
|
| 170 |
+
],
|
| 171 |
+
"total_distance": 2789.5,
|
| 172 |
+
"estimated_time": 46.5,
|
| 173 |
+
"algorithm": "Dijkstra",
|
| 174 |
+
"efficiency_score": 87.3
|
| 175 |
+
},
|
| 176 |
+
{
|
| 177 |
+
"route_id": 2,
|
| 178 |
+
"path": [
|
| 179 |
+
"New York",
|
| 180 |
+
"Pittsburgh",
|
| 181 |
+
"Chicago",
|
| 182 |
+
"Kansas City",
|
| 183 |
+
"Los Angeles"
|
| 184 |
+
],
|
| 185 |
+
"total_distance": 2834.2,
|
| 186 |
+
"estimated_time": 47.2,
|
| 187 |
+
"algorithm": "A*",
|
| 188 |
+
"efficiency_score": 85.1
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"route_id": 3,
|
| 192 |
+
"path": [
|
| 193 |
+
"New York",
|
| 194 |
+
"Cleveland",
|
| 195 |
+
"Chicago",
|
| 196 |
+
"Omaha",
|
| 197 |
+
"Denver",
|
| 198 |
+
"Los Angeles"
|
| 199 |
+
],
|
| 200 |
+
"total_distance": 2901.8,
|
| 201 |
+
"estimated_time": 48.4,
|
| 202 |
+
"algorithm": "A* (Weather-Adjusted)",
|
| 203 |
+
"efficiency_score": 83.7
|
| 204 |
+
}
|
| 205 |
+
],
|
| 206 |
+
"sample_alerts": [
|
| 207 |
+
{
|
| 208 |
+
"type": "HIGH_DELAY_RISK",
|
| 209 |
+
"severity": "HIGH",
|
| 210 |
+
"tracking_number": "TRK000001",
|
| 211 |
+
"message": "High delay risk (90.0%) for Houston -> Los Angeles",
|
| 212 |
+
"recommendations": [
|
| 213 |
+
"Consider alternative routing",
|
| 214 |
+
"Notify customer proactively",
|
| 215 |
+
"Monitor weather conditions"
|
| 216 |
+
]
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
"type": "HIGH_DELAY_RISK",
|
| 220 |
+
"severity": "HIGH",
|
| 221 |
+
"tracking_number": "TRK000002",
|
| 222 |
+
"message": "High delay risk (90.0%) for Dallas -> San Diego",
|
| 223 |
+
"recommendations": [
|
| 224 |
+
"Consider alternative routing",
|
| 225 |
+
"Notify customer proactively",
|
| 226 |
+
"Monitor weather conditions"
|
| 227 |
+
]
|
| 228 |
+
},
|
| 229 |
+
{
|
| 230 |
+
"type": "HIGH_DELAY_RISK",
|
| 231 |
+
"severity": "HIGH",
|
| 232 |
+
"tracking_number": "TRK000003",
|
| 233 |
+
"message": "High delay risk (82.5%) for Dallas -> Chicago",
|
| 234 |
+
"recommendations": [
|
| 235 |
+
"Consider alternative routing",
|
| 236 |
+
"Notify customer proactively",
|
| 237 |
+
"Monitor weather conditions"
|
| 238 |
+
]
|
| 239 |
+
},
|
| 240 |
+
{
|
| 241 |
+
"type": "HIGH_DELAY_RISK",
|
| 242 |
+
"severity": "HIGH",
|
| 243 |
+
"tracking_number": "TRK000004",
|
| 244 |
+
"message": "High delay risk (90.0%) for San Jose -> Philadelphia",
|
| 245 |
+
"recommendations": [
|
| 246 |
+
"Consider alternative routing",
|
| 247 |
+
"Notify customer proactively",
|
| 248 |
+
"Monitor weather conditions"
|
| 249 |
+
]
|
| 250 |
+
},
|
| 251 |
+
{
|
| 252 |
+
"type": "HIGH_DELAY_RISK",
|
| 253 |
+
"severity": "HIGH",
|
| 254 |
+
"tracking_number": "TRK000006",
|
| 255 |
+
"message": "High delay risk (90.0%) for Philadelphia -> Phoenix",
|
| 256 |
+
"recommendations": [
|
| 257 |
+
"Consider alternative routing",
|
| 258 |
+
"Notify customer proactively",
|
| 259 |
+
"Monitor weather conditions"
|
| 260 |
+
]
|
| 261 |
+
}
|
| 262 |
+
]
|
| 263 |
+
}
|
deploy.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Production Deployment Script for AI-Powered Shipment Route Optimization
|
| 4 |
+
Created by: Zayeem Khateeb
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
import sys
|
| 9 |
+
from src.dashboard.app import app
|
| 10 |
+
|
| 11 |
+
def create_production_app():
|
| 12 |
+
"""Configure app for production deployment"""
|
| 13 |
+
# Production optimizations
|
| 14 |
+
app.config.update(
|
| 15 |
+
DEBUG=False,
|
| 16 |
+
TESTING=False,
|
| 17 |
+
SECRET_KEY=os.environ.get('SECRET_KEY', 'production-secret-key-change-this'),
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
return app
|
| 21 |
+
|
| 22 |
+
if __name__ == '__main__':
|
| 23 |
+
# Get port from environment variable (for cloud deployment)
|
| 24 |
+
port = int(os.environ.get('PORT', 8050))
|
| 25 |
+
host = os.environ.get('HOST', '0.0.0.0')
|
| 26 |
+
|
| 27 |
+
print(f"🚀 Starting AI-Powered Shipment Route Optimization System")
|
| 28 |
+
print(f" Created by: Zayeem Khateeb")
|
| 29 |
+
print(f" Running on: http://{host}:{port}")
|
| 30 |
+
|
| 31 |
+
production_app = create_production_app()
|
| 32 |
+
production_app.run(host=host, port=port, debug=False)
|
docker-compose.yml
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version: '3.8'
|
| 2 |
+
|
| 3 |
+
services:
|
| 4 |
+
# GreenPath Streamlit Frontend
|
| 5 |
+
streamlit:
|
| 6 |
+
build:
|
| 7 |
+
context: .
|
| 8 |
+
dockerfile: Dockerfile.streamlit
|
| 9 |
+
ports:
|
| 10 |
+
- "8501:8501"
|
| 11 |
+
environment:
|
| 12 |
+
- DATABASE_URL=sqlite:///app/greenpath.db
|
| 13 |
+
- OPENROUTESERVICE_API_KEY=${OPENROUTESERVICE_API_KEY}
|
| 14 |
+
- FASTAPI_URL=http://fastapi:8000
|
| 15 |
+
volumes:
|
| 16 |
+
- ./data:/app/data
|
| 17 |
+
- ./greenpath.db:/app/greenpath.db
|
| 18 |
+
depends_on:
|
| 19 |
+
- fastapi
|
| 20 |
+
restart: unless-stopped
|
| 21 |
+
|
| 22 |
+
# GreenPath FastAPI Backend
|
| 23 |
+
fastapi:
|
| 24 |
+
build:
|
| 25 |
+
context: .
|
| 26 |
+
dockerfile: Dockerfile.fastapi
|
| 27 |
+
ports:
|
| 28 |
+
- "8000:8000"
|
| 29 |
+
environment:
|
| 30 |
+
- DATABASE_URL=sqlite:///app/greenpath.db
|
| 31 |
+
- OPENROUTESERVICE_API_KEY=${OPENROUTESERVICE_API_KEY}
|
| 32 |
+
volumes:
|
| 33 |
+
- ./data:/app/data
|
| 34 |
+
- ./greenpath.db:/app/greenpath.db
|
| 35 |
+
restart: unless-stopped
|
| 36 |
+
|
| 37 |
+
# PostgreSQL Database (Optional - for production)
|
| 38 |
+
postgres:
|
| 39 |
+
image: postgres:13
|
| 40 |
+
environment:
|
| 41 |
+
- POSTGRES_DB=greenpath
|
| 42 |
+
- POSTGRES_USER=greenpath_user
|
| 43 |
+
- POSTGRES_PASSWORD=secure_greenpath_password
|
| 44 |
+
volumes:
|
| 45 |
+
- postgres_data:/var/lib/postgresql/data
|
| 46 |
+
ports:
|
| 47 |
+
- "5432:5432"
|
| 48 |
+
restart: unless-stopped
|
| 49 |
+
# Redis for caching (optional)
|
| 50 |
+
redis:
|
| 51 |
+
image: redis:7-alpine
|
| 52 |
+
ports:
|
| 53 |
+
- "6379:6379"
|
| 54 |
+
restart: unless-stopped
|
| 55 |
+
networks:
|
| 56 |
+
- shipment_network
|
| 57 |
+
|
| 58 |
+
volumes:
|
| 59 |
+
postgres_data:
|
| 60 |
+
|
| 61 |
+
networks:
|
| 62 |
+
shipment_network:
|
| 63 |
+
driver: bridge
|
game.js
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 2 |
+
const gridContainer = document.querySelector('.grid-container');
|
| 3 |
+
const scoreElement = document.getElementById('score');
|
| 4 |
+
const bestScoreElement = document.getElementById('best-score');
|
| 5 |
+
const newGameButton = document.getElementById('new-game');
|
| 6 |
+
const tryAgainButton = document.getElementById('try-again');
|
| 7 |
+
const keepGoingButton = document.getElementById('keep-going');
|
| 8 |
+
const gameOverScreen = document.querySelector('.game-over');
|
| 9 |
+
const gameWonScreen = document.querySelector('.game-won');
|
| 10 |
+
|
| 11 |
+
let grid = [];
|
| 12 |
+
let score = 0;
|
| 13 |
+
let bestScore = localStorage.getItem('bestScore') || 0;
|
| 14 |
+
let gameOver = false;
|
| 15 |
+
let gameWon = false;
|
| 16 |
+
|
| 17 |
+
// Initialize the game
|
| 18 |
+
function initGame() {
|
| 19 |
+
// Clear the grid
|
| 20 |
+
grid = Array(4).fill().map(() => Array(4).fill(0));
|
| 21 |
+
score = 0;
|
| 22 |
+
gameOver = false;
|
| 23 |
+
gameWon = false;
|
| 24 |
+
|
| 25 |
+
// Clear the grid container
|
| 26 |
+
gridContainer.innerHTML = '';
|
| 27 |
+
|
| 28 |
+
// Create the grid cells
|
| 29 |
+
for (let i = 0; i < 4; i++) {
|
| 30 |
+
for (let j = 0; j < 4; j++) {
|
| 31 |
+
const cell = document.createElement('div');
|
| 32 |
+
cell.className = 'grid-cell';
|
| 33 |
+
gridContainer.appendChild(cell);
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
// Add initial tiles
|
| 38 |
+
addRandomTile();
|
| 39 |
+
addRandomTile();
|
| 40 |
+
|
| 41 |
+
// Update the score display
|
| 42 |
+
updateScore();
|
| 43 |
+
|
| 44 |
+
// Hide game over/win screens
|
| 45 |
+
gameOverScreen.style.display = 'none';
|
| 46 |
+
gameWonScreen.style.display = 'none';
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
// Add a random tile (2 or 4) to an empty cell
|
| 50 |
+
function addRandomTile() {
|
| 51 |
+
const emptyCells = [];
|
| 52 |
+
|
| 53 |
+
// Find all empty cells
|
| 54 |
+
for (let i = 0; i < 4; i++) {
|
| 55 |
+
for (let j = 0; j < 4; j++) {
|
| 56 |
+
if (grid[i][j] === 0) {
|
| 57 |
+
emptyCells.push({x: i, y: j});
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
if (emptyCells.length > 0) {
|
| 63 |
+
// Choose a random empty cell
|
| 64 |
+
const {x, y} = emptyCells[Math.floor(Math.random() * emptyCells.length)];
|
| 65 |
+
// 90% chance for 2, 10% chance for 4
|
| 66 |
+
grid[x][y] = Math.random() < 0.9 ? 2 : 4;
|
| 67 |
+
|
| 68 |
+
// Create and animate the new tile
|
| 69 |
+
createTile(x, y, grid[x][y], true);
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
// Create a tile element at the specified position
|
| 74 |
+
function createTile(x, y, value, isNew = false) {
|
| 75 |
+
const tile = document.createElement('div');
|
| 76 |
+
tile.className = `tile tile-${value} ${isNew ? 'new-tile' : ''}`;
|
| 77 |
+
tile.textContent = value;
|
| 78 |
+
|
| 79 |
+
// Position the tile
|
| 80 |
+
const posX = y * 25 + (y * 15);
|
| 81 |
+
const posY = x * 25 + (x * 15);
|
| 82 |
+
|
| 83 |
+
tile.style.left = `${posX}%`;
|
| 84 |
+
tile.style.top = `${posY}%`;
|
| 85 |
+
|
| 86 |
+
// Add data attributes for tracking position
|
| 87 |
+
tile.dataset.x = x;
|
| 88 |
+
tile.dataset.y = y;
|
| 89 |
+
tile.dataset.value = value;
|
| 90 |
+
|
| 91 |
+
gridContainer.appendChild(tile);
|
| 92 |
+
return tile;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
// Update the score display
|
| 96 |
+
function updateScore() {
|
| 97 |
+
scoreElement.textContent = score;
|
| 98 |
+
bestScore = Math.max(score, bestScore);
|
| 99 |
+
bestScoreElement.textContent = bestScore;
|
| 100 |
+
localStorage.setItem('bestScore', bestScore);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
// Check if there are any moves left
|
| 104 |
+
function hasMovesLeft() {
|
| 105 |
+
// Check for any empty cells
|
| 106 |
+
for (let i = 0; i < 4; i++) {
|
| 107 |
+
for (let j = 0; j < 4; j++) {
|
| 108 |
+
if (grid[i][j] === 0) return true;
|
| 109 |
+
|
| 110 |
+
// Check adjacent cells for possible merges
|
| 111 |
+
if (i < 3 && grid[i][j] === grid[i + 1][j]) return true;
|
| 112 |
+
if (j < 3 && grid[i][j] === grid[i][j + 1]) return true;
|
| 113 |
+
}
|
| 114 |
+
}
|
| 115 |
+
return false;
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
// Move tiles in the specified direction
|
| 119 |
+
function moveTiles(direction) {
|
| 120 |
+
if (gameOver || gameWon) return false;
|
| 121 |
+
|
| 122 |
+
let moved = false;
|
| 123 |
+
const oldGrid = JSON.parse(JSON.stringify(grid));
|
| 124 |
+
|
| 125 |
+
// Remove all tiles from the DOM (we'll recreate them after moving)
|
| 126 |
+
const tiles = document.querySelectorAll('.tile');
|
| 127 |
+
const tilesData = Array.from(tiles).map(tile => ({
|
| 128 |
+
x: parseInt(tile.dataset.x),
|
| 129 |
+
y: parseInt(tile.dataset.y),
|
| 130 |
+
value: parseInt(tile.dataset.value),
|
| 131 |
+
element: tile
|
| 132 |
+
}));
|
| 133 |
+
|
| 134 |
+
tiles.forEach(tile => tile.remove());
|
| 135 |
+
|
| 136 |
+
// Process the move based on direction
|
| 137 |
+
switch (direction) {
|
| 138 |
+
case 'up':
|
| 139 |
+
moved = moveUp();
|
| 140 |
+
break;
|
| 141 |
+
case 'right':
|
| 142 |
+
moved = moveRight();
|
| 143 |
+
break;
|
| 144 |
+
case 'down':
|
| 145 |
+
moved = moveDown();
|
| 146 |
+
break;
|
| 147 |
+
case 'left':
|
| 148 |
+
moved = moveLeft();
|
| 149 |
+
break;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
// If the grid changed, add a new random tile
|
| 153 |
+
if (moved) {
|
| 154 |
+
addRandomTile();
|
| 155 |
+
updateScore();
|
| 156 |
+
|
| 157 |
+
// Check for win condition
|
| 158 |
+
if (!gameWon && checkWin()) {
|
| 159 |
+
gameWon = true;
|
| 160 |
+
gameWonScreen.style.display = 'flex';
|
| 161 |
+
}
|
| 162 |
+
// Check for game over
|
| 163 |
+
else if (!hasMovesLeft()) {
|
| 164 |
+
gameOver = true;
|
| 165 |
+
gameOverScreen.style.display = 'flex';
|
| 166 |
+
}
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
// Recreate tiles with new positions
|
| 170 |
+
for (let i = 0; i < 4; i++) {
|
| 171 |
+
for (let j = 0; j < 4; j++) {
|
| 172 |
+
if (grid[i][j] !== 0) {
|
| 173 |
+
createTile(i, j, grid[i][j]);
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
return moved;
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
// Move tiles up
|
| 182 |
+
function moveUp() {
|
| 183 |
+
let moved = false;
|
| 184 |
+
|
| 185 |
+
for (let j = 0; j < 4; j++) {
|
| 186 |
+
// Move all tiles up as much as possible
|
| 187 |
+
for (let i = 1; i < 4; i++) {
|
| 188 |
+
if (grid[i][j] !== 0) {
|
| 189 |
+
let row = i;
|
| 190 |
+
while (row > 0 && grid[row - 1][j] === 0) {
|
| 191 |
+
grid[row - 1][j] = grid[row][j];
|
| 192 |
+
grid[row][j] = 0;
|
| 193 |
+
row--;
|
| 194 |
+
moved = true;
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
// Check for merge with the tile above
|
| 198 |
+
if (row > 0 && grid[row - 1][j] === grid[row][j] &&
|
| 199 |
+
!document.querySelector(`.tile[data-x="${row-1}"][data-y="${j}"].merged`)) {
|
| 200 |
+
grid[row - 1][j] *= 2;
|
| 201 |
+
score += grid[row - 1][j];
|
| 202 |
+
grid[row][j] = 0;
|
| 203 |
+
moved = true;
|
| 204 |
+
}
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
return moved;
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
// Move tiles right
|
| 213 |
+
function moveRight() {
|
| 214 |
+
let moved = false;
|
| 215 |
+
|
| 216 |
+
for (let i = 0; i < 4; i++) {
|
| 217 |
+
for (let j = 2; j >= 0; j--) {
|
| 218 |
+
if (grid[i][j] !== 0) {
|
| 219 |
+
let col = j;
|
| 220 |
+
while (col < 3 && grid[i][col + 1] === 0) {
|
| 221 |
+
grid[i][col + 1] = grid[i][col];
|
| 222 |
+
grid[i][col] = 0;
|
| 223 |
+
col++;
|
| 224 |
+
moved = true;
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
// Check for merge with the tile to the right
|
| 228 |
+
if (col < 3 && grid[i][col + 1] === grid[i][col] &&
|
| 229 |
+
!document.querySelector(`.tile[data-x="${i}"][data-y="${col+1}"].merged`)) {
|
| 230 |
+
grid[i][col + 1] *= 2;
|
| 231 |
+
score += grid[i][col + 1];
|
| 232 |
+
grid[i][col] = 0;
|
| 233 |
+
moved = true;
|
| 234 |
+
}
|
| 235 |
+
}
|
| 236 |
+
}
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
return moved;
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
+
// Move tiles down
|
| 243 |
+
function moveDown() {
|
| 244 |
+
let moved = false;
|
| 245 |
+
|
| 246 |
+
for (let j = 0; j < 4; j++) {
|
| 247 |
+
for (let i = 2; i >= 0; i--) {
|
| 248 |
+
if (grid[i][j] !== 0) {
|
| 249 |
+
let row = i;
|
| 250 |
+
while (row < 3 && grid[row + 1][j] === 0) {
|
| 251 |
+
grid[row + 1][j] = grid[row][j];
|
| 252 |
+
grid[row][j] = 0;
|
| 253 |
+
row++;
|
| 254 |
+
moved = true;
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
// Check for merge with the tile below
|
| 258 |
+
if (row < 3 && grid[row + 1][j] === grid[row][j] &&
|
| 259 |
+
!document.querySelector(`.tile[data-x="${row+1}"][data-y="${j}"].merged`)) {
|
| 260 |
+
grid[row + 1][j] *= 2;
|
| 261 |
+
score += grid[row + 1][j];
|
| 262 |
+
grid[row][j] = 0;
|
| 263 |
+
moved = true;
|
| 264 |
+
}
|
| 265 |
+
}
|
| 266 |
+
}
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
return moved;
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
// Move tiles left
|
| 273 |
+
function moveLeft() {
|
| 274 |
+
let moved = false;
|
| 275 |
+
|
| 276 |
+
for (let i = 0; i < 4; i++) {
|
| 277 |
+
for (let j = 1; j < 4; j++) {
|
| 278 |
+
if (grid[i][j] !== 0) {
|
| 279 |
+
let col = j;
|
| 280 |
+
while (col > 0 && grid[i][col - 1] === 0) {
|
| 281 |
+
grid[i][col - 1] = grid[i][col];
|
| 282 |
+
grid[i][col] = 0;
|
| 283 |
+
col--;
|
| 284 |
+
moved = true;
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
// Check for merge with the tile to the left
|
| 288 |
+
if (col > 0 && grid[i][col - 1] === grid[i][col] &&
|
| 289 |
+
!document.querySelector(`.tile[data-x="${i}"][data-y="${col-1}"].merged`)) {
|
| 290 |
+
grid[i][col - 1] *= 2;
|
| 291 |
+
score += grid[i][col - 1];
|
| 292 |
+
grid[i][col] = 0;
|
| 293 |
+
moved = true;
|
| 294 |
+
}
|
| 295 |
+
}
|
| 296 |
+
}
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
return moved;
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
// Check if the player has won (reached 2048)
|
| 303 |
+
function checkWin() {
|
| 304 |
+
for (let i = 0; i < 4; i++) {
|
| 305 |
+
for (let j = 0; j < 4; j++) {
|
| 306 |
+
if (grid[i][j] === 2048) {
|
| 307 |
+
return true;
|
| 308 |
+
}
|
| 309 |
+
}
|
| 310 |
+
}
|
| 311 |
+
return false;
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
// Event listeners
|
| 315 |
+
document.addEventListener('keydown', (e) => {
|
| 316 |
+
switch (e.key) {
|
| 317 |
+
case 'ArrowUp':
|
| 318 |
+
e.preventDefault();
|
| 319 |
+
moveTiles('up');
|
| 320 |
+
break;
|
| 321 |
+
case 'ArrowRight':
|
| 322 |
+
e.preventDefault();
|
| 323 |
+
moveTiles('right');
|
| 324 |
+
break;
|
| 325 |
+
case 'ArrowDown':
|
| 326 |
+
e.preventDefault();
|
| 327 |
+
moveTiles('down');
|
| 328 |
+
break;
|
| 329 |
+
case 'ArrowLeft':
|
| 330 |
+
e.preventDefault();
|
| 331 |
+
moveTiles('left');
|
| 332 |
+
break;
|
| 333 |
+
}
|
| 334 |
+
});
|
| 335 |
+
|
| 336 |
+
// Touch support for mobile devices
|
| 337 |
+
let touchStartX = 0;
|
| 338 |
+
let touchStartY = 0;
|
| 339 |
+
let touchEndX = 0;
|
| 340 |
+
let touchEndY = 0;
|
| 341 |
+
|
| 342 |
+
document.addEventListener('touchstart', (e) => {
|
| 343 |
+
touchStartX = e.touches[0].clientX;
|
| 344 |
+
touchStartY = e.touches[0].clientY;
|
| 345 |
+
}, false);
|
| 346 |
+
|
| 347 |
+
document.addEventListener('touchend', (e) => {
|
| 348 |
+
touchEndX = e.changedTouches[0].clientX;
|
| 349 |
+
touchEndY = e.changedTouches[0].clientY;
|
| 350 |
+
handleSwipe();
|
| 351 |
+
}, false);
|
| 352 |
+
|
| 353 |
+
function handleSwipe() {
|
| 354 |
+
const dx = touchEndX - touchStartX;
|
| 355 |
+
const dy = touchEndY - touchStartY;
|
| 356 |
+
|
| 357 |
+
// Determine if the swipe was more horizontal or vertical
|
| 358 |
+
if (Math.abs(dx) > Math.abs(dy)) {
|
| 359 |
+
// Horizontal swipe
|
| 360 |
+
if (dx > 0) {
|
| 361 |
+
moveTiles('right');
|
| 362 |
+
} else {
|
| 363 |
+
moveTiles('left');
|
| 364 |
+
}
|
| 365 |
+
} else {
|
| 366 |
+
// Vertical swipe
|
| 367 |
+
if (dy > 0) {
|
| 368 |
+
moveTiles('down');
|
| 369 |
+
} else {
|
| 370 |
+
moveTiles('up');
|
| 371 |
+
}
|
| 372 |
+
}
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
// Button event listeners
|
| 376 |
+
newGameButton.addEventListener('click', initGame);
|
| 377 |
+
tryAgainButton.addEventListener('click', initGame);
|
| 378 |
+
keepGoingButton.addEventListener('click', () => {
|
| 379 |
+
gameWonScreen.style.display = 'none';
|
| 380 |
+
gameWon = false;
|
| 381 |
+
});
|
| 382 |
+
|
| 383 |
+
// Initialize the game
|
| 384 |
+
initGame();
|
| 385 |
+
});
|
index.html
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>2048 Game</title>
|
| 7 |
+
<link rel="stylesheet" href="styles.css">
|
| 8 |
+
</head>
|
| 9 |
+
<body>
|
| 10 |
+
<div class="container">
|
| 11 |
+
<div class="header">
|
| 12 |
+
<h1>2048</h1>
|
| 13 |
+
<div class="scores">
|
| 14 |
+
<div class="score-box">
|
| 15 |
+
<div class="score-title">SCORE</div>
|
| 16 |
+
<div id="score">0</div>
|
| 17 |
+
</div>
|
| 18 |
+
<div class="score-box">
|
| 19 |
+
<div class="score-title">BEST</div>
|
| 20 |
+
<div id="best-score">0</div>
|
| 21 |
+
</div>
|
| 22 |
+
</div>
|
| 23 |
+
</div>
|
| 24 |
+
<div class="game-intro">
|
| 25 |
+
<p>Join the tiles, get to <strong>2048!</strong></p>
|
| 26 |
+
<button id="new-game">New Game</button>
|
| 27 |
+
</div>
|
| 28 |
+
<div class="game-container">
|
| 29 |
+
<div class="grid-container"></div>
|
| 30 |
+
<div class="game-over">
|
| 31 |
+
<p>Game Over!</p>
|
| 32 |
+
<button id="try-again">Try Again</button>
|
| 33 |
+
</div>
|
| 34 |
+
<div class="game-won">
|
| 35 |
+
<p>You Win!</p>
|
| 36 |
+
<button id="keep-going">Keep Going</button>
|
| 37 |
+
</div>
|
| 38 |
+
</div>
|
| 39 |
+
<p class="game-explanation">
|
| 40 |
+
<strong>HOW TO PLAY:</strong> Use your <strong>arrow keys</strong> to move the tiles. When two tiles with the same number touch, they <strong>merge into one!</strong>
|
| 41 |
+
</p>
|
| 42 |
+
</div>
|
| 43 |
+
<script src="game.js"></script>
|
| 44 |
+
</body>
|
| 45 |
+
</html>
|
main.py
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
AI-Powered Shipment Route Optimization & Delay Prediction System
|
| 4 |
+
Main application entry point for demonstration and testing
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import sys
|
| 8 |
+
import os
|
| 9 |
+
import pandas as pd
|
| 10 |
+
from datetime import datetime
|
| 11 |
+
|
| 12 |
+
# Add src directory to path
|
| 13 |
+
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
|
| 14 |
+
|
| 15 |
+
from data_pipeline.data_collector import DataCollector
|
| 16 |
+
from data_pipeline.data_processor import DataProcessor
|
| 17 |
+
from ml_models.delay_predictor import DelayPredictor, ModelEvaluator
|
| 18 |
+
from route_optimizer.route_optimizer import RouteOptimizer, RouteAnalyzer
|
| 19 |
+
from utils.monitoring import ShipmentMonitor, PerformanceAnalyzer
|
| 20 |
+
|
| 21 |
+
def demonstrate_system():
|
| 22 |
+
"""Demonstrate the complete AI-powered shipment optimization system"""
|
| 23 |
+
|
| 24 |
+
print("=" * 60)
|
| 25 |
+
print("AI-POWERED SHIPMENT ROUTE OPTIMIZATION & DELAY PREDICTION")
|
| 26 |
+
print("=" * 60)
|
| 27 |
+
print()
|
| 28 |
+
|
| 29 |
+
# Initialize components
|
| 30 |
+
print("🔧 Initializing system components...")
|
| 31 |
+
data_collector = DataCollector()
|
| 32 |
+
data_processor = DataProcessor()
|
| 33 |
+
delay_predictor = DelayPredictor()
|
| 34 |
+
route_optimizer = RouteOptimizer()
|
| 35 |
+
monitor = ShipmentMonitor()
|
| 36 |
+
analyzer = PerformanceAnalyzer()
|
| 37 |
+
|
| 38 |
+
# Step 1: Data Collection and Processing
|
| 39 |
+
print("\n📊 STEP 1: Data Collection and Processing")
|
| 40 |
+
print("-" * 40)
|
| 41 |
+
|
| 42 |
+
# Generate sample data for demonstration
|
| 43 |
+
print("Generating sample shipment data...")
|
| 44 |
+
sample_data = data_processor.generate_sample_data(1000)
|
| 45 |
+
print(f"✅ Generated {len(sample_data)} sample shipments")
|
| 46 |
+
|
| 47 |
+
# Clean and process data
|
| 48 |
+
print("Cleaning and processing data...")
|
| 49 |
+
processed_data = data_processor.clean_shipment_data(sample_data)
|
| 50 |
+
feature_data = data_processor.create_features(processed_data)
|
| 51 |
+
print(f"✅ Processed data with {len(feature_data.columns)} features")
|
| 52 |
+
|
| 53 |
+
# Step 2: Machine Learning Model Training
|
| 54 |
+
print("\n🤖 STEP 2: Machine Learning Model Training")
|
| 55 |
+
print("-" * 40)
|
| 56 |
+
|
| 57 |
+
# Prepare data for ML
|
| 58 |
+
X, y = data_processor.prepare_ml_data(feature_data)
|
| 59 |
+
print(f"Training data shape: {X.shape}")
|
| 60 |
+
print(f"Target distribution: {y.value_counts().to_dict()}")
|
| 61 |
+
|
| 62 |
+
# Train delay prediction model
|
| 63 |
+
print("\nTraining XGBoost delay prediction model...")
|
| 64 |
+
metrics = delay_predictor.train_model(X, y)
|
| 65 |
+
print(f"✅ Model trained with {metrics['accuracy']:.1%} accuracy")
|
| 66 |
+
|
| 67 |
+
# Step 3: Route Optimization
|
| 68 |
+
print("\n🗺️ STEP 3: Route Optimization")
|
| 69 |
+
print("-" * 40)
|
| 70 |
+
|
| 71 |
+
# Build sample route network
|
| 72 |
+
print("Building route optimization network...")
|
| 73 |
+
# Add major US cities as nodes
|
| 74 |
+
cities = {
|
| 75 |
+
'NYC': (40.7128, -74.0060),
|
| 76 |
+
'LA': (34.0522, -118.2437),
|
| 77 |
+
'CHI': (41.8781, -87.6298),
|
| 78 |
+
'HOU': (29.7604, -95.3698),
|
| 79 |
+
'PHX': (33.4484, -112.0740)
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
for city_id, (lat, lng) in cities.items():
|
| 83 |
+
route_optimizer.add_location(city_id, lat, lng, 'city')
|
| 84 |
+
|
| 85 |
+
# Add routes between cities
|
| 86 |
+
city_pairs = [
|
| 87 |
+
('NYC', 'CHI'), ('CHI', 'LA'), ('NYC', 'HOU'),
|
| 88 |
+
('HOU', 'LA'), ('CHI', 'PHX'), ('PHX', 'LA')
|
| 89 |
+
]
|
| 90 |
+
|
| 91 |
+
for city1, city2 in city_pairs:
|
| 92 |
+
route_optimizer.add_route(city1, city2)
|
| 93 |
+
|
| 94 |
+
print(f"✅ Built network with {len(cities)} cities and {len(city_pairs)} routes")
|
| 95 |
+
|
| 96 |
+
# Find optimal routes
|
| 97 |
+
print("\nFinding optimal routes NYC -> LA...")
|
| 98 |
+
routes = route_optimizer.find_alternative_routes('NYC', 'LA', num_alternatives=3)
|
| 99 |
+
|
| 100 |
+
for i, route in enumerate(routes[:3]):
|
| 101 |
+
if 'error' not in route:
|
| 102 |
+
print(f"Route {i+1}: {' -> '.join(route['path'])} "
|
| 103 |
+
f"({route['total_cost']:.1f} minutes)")
|
| 104 |
+
|
| 105 |
+
# Step 4: Delay Prediction Demo
|
| 106 |
+
print("\n🎯 STEP 4: Delay Risk Prediction")
|
| 107 |
+
print("-" * 40)
|
| 108 |
+
|
| 109 |
+
# Predict delays for sample shipments
|
| 110 |
+
sample_shipments = feature_data.head(10)
|
| 111 |
+
X_sample, _ = data_processor.prepare_ml_data(sample_shipments)
|
| 112 |
+
|
| 113 |
+
if len(X_sample) > 0:
|
| 114 |
+
risk_predictions = delay_predictor.predict_delay_risk(X_sample)
|
| 115 |
+
|
| 116 |
+
print("Sample delay risk predictions:")
|
| 117 |
+
for i in range(min(5, len(risk_predictions))):
|
| 118 |
+
tracking = sample_shipments.iloc[i]['tracking_number']
|
| 119 |
+
risk = risk_predictions.iloc[i]['risk_category']
|
| 120 |
+
prob = risk_predictions.iloc[i]['delay_probability']
|
| 121 |
+
print(f" {tracking}: {risk} ({prob:.1%} probability)")
|
| 122 |
+
|
| 123 |
+
# Step 5: Real-time Monitoring
|
| 124 |
+
print("\n📡 STEP 5: Real-time Monitoring")
|
| 125 |
+
print("-" * 40)
|
| 126 |
+
|
| 127 |
+
# Simulate monitoring
|
| 128 |
+
print("Running shipment monitoring system...")
|
| 129 |
+
monitoring_results = monitor.monitor_shipments()
|
| 130 |
+
|
| 131 |
+
print(f"✅ Monitoring complete:")
|
| 132 |
+
print(f" - Active shipments: {monitoring_results['summary'].get('total_active_shipments', 0)}")
|
| 133 |
+
print(f" - Total alerts: {monitoring_results['summary'].get('total_alerts', 0)}")
|
| 134 |
+
print(f" - High risk shipments: {monitoring_results['summary'].get('high_risk_shipments', 0)}")
|
| 135 |
+
|
| 136 |
+
# Step 6: Performance Analysis
|
| 137 |
+
print("\n📈 STEP 6: Performance Analysis")
|
| 138 |
+
print("-" * 40)
|
| 139 |
+
|
| 140 |
+
performance = analyzer.analyze_delivery_performance(30)
|
| 141 |
+
bottlenecks = analyzer.identify_bottlenecks()
|
| 142 |
+
|
| 143 |
+
if 'error' not in performance:
|
| 144 |
+
print(f"✅ 30-day performance analysis:")
|
| 145 |
+
print(f" - Total shipments: {performance.get('total_shipments', 0)}")
|
| 146 |
+
print(f" - On-time rate: {performance.get('on_time_rate_percent', 0):.1f}%")
|
| 147 |
+
print(f" - Average delay: {performance.get('average_delay_minutes', 0):.1f} minutes")
|
| 148 |
+
|
| 149 |
+
print(f"\n🔍 Top delay causes identified:")
|
| 150 |
+
for cause in bottlenecks['top_delay_causes'][:3]:
|
| 151 |
+
print(f" - {cause['cause']}: {cause['frequency']} incidents, "
|
| 152 |
+
f"{cause['avg_delay_minutes']} min avg delay")
|
| 153 |
+
|
| 154 |
+
# Step 7: Business Impact Summary
|
| 155 |
+
print("\n💼 STEP 7: Business Impact Summary")
|
| 156 |
+
print("-" * 40)
|
| 157 |
+
|
| 158 |
+
print("🎯 Key Achievements:")
|
| 159 |
+
print(f" ✅ Predictive model accuracy: {metrics['accuracy']:.1%}")
|
| 160 |
+
print(f" ✅ Route optimization: {len(routes)} alternative routes found")
|
| 161 |
+
print(f" ✅ Real-time monitoring: Active alert system")
|
| 162 |
+
print(f" ✅ Performance analytics: Bottleneck identification")
|
| 163 |
+
|
| 164 |
+
print("\n📊 Expected Business Benefits:")
|
| 165 |
+
print(" • 15% reduction in delivery delays")
|
| 166 |
+
print(" • Improved customer satisfaction through proactive notifications")
|
| 167 |
+
print(" • Real-time visibility into shipment status")
|
| 168 |
+
print(" • Data-driven decision making for logistics operations")
|
| 169 |
+
|
| 170 |
+
print("\n🚀 System Ready!")
|
| 171 |
+
print("Dashboard available at: http://localhost:8050")
|
| 172 |
+
print("Run 'python src/dashboard/app.py' to start the web interface")
|
| 173 |
+
|
| 174 |
+
return {
|
| 175 |
+
'model_accuracy': metrics['accuracy'],
|
| 176 |
+
'routes_found': len(routes),
|
| 177 |
+
'monitoring_active': True,
|
| 178 |
+
'system_status': 'operational'
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
def run_dashboard():
|
| 182 |
+
"""Launch the web dashboard"""
|
| 183 |
+
print("🚀 Starting AI-Powered Shipment Optimization Dashboard...")
|
| 184 |
+
|
| 185 |
+
try:
|
| 186 |
+
from dashboard.app import app
|
| 187 |
+
print("Dashboard starting at http://localhost:8050")
|
| 188 |
+
app.run_server(debug=False, host='0.0.0.0', port=8050)
|
| 189 |
+
except ImportError as e:
|
| 190 |
+
print(f"Error importing dashboard: {e}")
|
| 191 |
+
print("Please install required dependencies: pip install -r requirements.txt")
|
| 192 |
+
except Exception as e:
|
| 193 |
+
print(f"Error starting dashboard: {e}")
|
| 194 |
+
|
| 195 |
+
if __name__ == "__main__":
|
| 196 |
+
import argparse
|
| 197 |
+
|
| 198 |
+
parser = argparse.ArgumentParser(description='AI-Powered Shipment Route Optimization System')
|
| 199 |
+
parser.add_argument('--demo', action='store_true', help='Run system demonstration')
|
| 200 |
+
parser.add_argument('--dashboard', action='store_true', help='Start web dashboard')
|
| 201 |
+
parser.add_argument('--all', action='store_true', help='Run demo then start dashboard')
|
| 202 |
+
|
| 203 |
+
args = parser.parse_args()
|
| 204 |
+
|
| 205 |
+
if args.demo or args.all:
|
| 206 |
+
results = demonstrate_system()
|
| 207 |
+
print(f"\nDemo completed. Results: {results}")
|
| 208 |
+
|
| 209 |
+
if args.dashboard or args.all:
|
| 210 |
+
if args.all:
|
| 211 |
+
print("\n" + "="*60)
|
| 212 |
+
input("Press Enter to start the dashboard...")
|
| 213 |
+
run_dashboard()
|
| 214 |
+
|
| 215 |
+
if not any([args.demo, args.dashboard, args.all]):
|
| 216 |
+
print("AI-Powered Shipment Route Optimization System")
|
| 217 |
+
print("Usage:")
|
| 218 |
+
print(" python main.py --demo # Run demonstration")
|
| 219 |
+
print(" python main.py --dashboard # Start web dashboard")
|
| 220 |
+
print(" python main.py --all # Run demo then dashboard")
|
netlify.toml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[build]
|
| 2 |
+
base = "."
|
| 3 |
+
publish = "."
|
| 4 |
+
command = "pip install -r requirements.txt"
|
| 5 |
+
|
| 6 |
+
[build.environment]
|
| 7 |
+
PYTHON_VERSION = "3.11"
|
| 8 |
+
|
| 9 |
+
[[redirects]]
|
| 10 |
+
from = "/*"
|
| 11 |
+
to = "/deploy.py"
|
| 12 |
+
status = 200
|
| 13 |
+
|
| 14 |
+
[context.production.environment]
|
| 15 |
+
FLASK_ENV = "production"
|
| 16 |
+
|
| 17 |
+
[context.deploy-preview.environment]
|
| 18 |
+
FLASK_ENV = "development"
|
render.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
- type: web
|
| 3 |
+
name: greenpath-ai
|
| 4 |
+
env: python
|
| 5 |
+
pythonVersion: "3.11"
|
| 6 |
+
buildCommand: "pip install -r requirements.txt"
|
| 7 |
+
startCommand: "gunicorn myapp.wsgi"
|
requirements.txt
CHANGED
|
@@ -1,23 +1,24 @@
|
|
| 1 |
-
streamlit
|
| 2 |
-
pandas==2.1.3
|
| 3 |
-
numpy==1.25.2
|
| 4 |
-
scikit-learn==1.3.2
|
| 5 |
-
xgboost>=1.6.0
|
| 6 |
-
requests==2.31.0
|
| 7 |
-
fastapi==0.104.1
|
| 8 |
-
uvicorn==0.24.0
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
snowflake-
|
|
|
|
|
|
| 1 |
+
streamlit
|
| 2 |
+
pandas==2.1.3
|
| 3 |
+
numpy==1.25.2
|
| 4 |
+
scikit-learn==1.3.2
|
| 5 |
+
xgboost>=1.6.0
|
| 6 |
+
requests==2.31.0
|
| 7 |
+
fastapi==0.104.1
|
| 8 |
+
uvicorn==0.24.0
|
| 9 |
+
streamlit==1.28.1
|
| 10 |
+
plotly==5.17.0
|
| 11 |
+
geopy==2.4.0
|
| 12 |
+
python-dotenv==1.0.0
|
| 13 |
+
networkx>=2.8
|
| 14 |
+
openrouteservice==2.3.3
|
| 15 |
+
sqlalchemy==2.0.23
|
| 16 |
+
pydantic==2.5.0
|
| 17 |
+
folium==0.15.0
|
| 18 |
+
streamlit-folium==0.15.0
|
| 19 |
+
reportlab==4.0.7
|
| 20 |
+
openpyxl==3.1.2
|
| 21 |
+
psycopg2-binary==2.9.9
|
| 22 |
+
redis==5.0.1
|
| 23 |
+
snowflake-connector-python==3.6.0
|
| 24 |
+
snowflake-sqlalchemy==1.5.1
|
styles.css
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
* {
|
| 2 |
+
margin: 0;
|
| 3 |
+
padding: 0;
|
| 4 |
+
box-sizing: border-box;
|
| 5 |
+
font-family: Arial, sans-serif;
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
body {
|
| 9 |
+
background-color: #faf8ef;
|
| 10 |
+
color: #776e65;
|
| 11 |
+
line-height: 1.4;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.container {
|
| 15 |
+
max-width: 500px;
|
| 16 |
+
margin: 0 auto;
|
| 17 |
+
padding: 20px;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
.header {
|
| 21 |
+
display: flex;
|
| 22 |
+
justify-content: space-between;
|
| 23 |
+
align-items: center;
|
| 24 |
+
margin-bottom: 20px;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
h1 {
|
| 28 |
+
font-size: 80px;
|
| 29 |
+
font-weight: bold;
|
| 30 |
+
color: #776e65;
|
| 31 |
+
margin: 0;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
.scores {
|
| 35 |
+
display: flex;
|
| 36 |
+
gap: 10px;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
.score-box {
|
| 40 |
+
background: #bbada0;
|
| 41 |
+
color: white;
|
| 42 |
+
padding: 5px 15px;
|
| 43 |
+
border-radius: 3px;
|
| 44 |
+
text-align: center;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
.score-title {
|
| 48 |
+
font-size: 13px;
|
| 49 |
+
text-transform: uppercase;
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
#score, #best-score {
|
| 53 |
+
font-size: 22px;
|
| 54 |
+
font-weight: bold;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
.game-intro {
|
| 58 |
+
display: flex;
|
| 59 |
+
justify-content: space-between;
|
| 60 |
+
align-items: center;
|
| 61 |
+
margin-bottom: 20px;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
button {
|
| 65 |
+
background: #8f7a66;
|
| 66 |
+
color: white;
|
| 67 |
+
border: none;
|
| 68 |
+
border-radius: 3px;
|
| 69 |
+
padding: 10px 20px;
|
| 70 |
+
font-size: 18px;
|
| 71 |
+
font-weight: bold;
|
| 72 |
+
cursor: pointer;
|
| 73 |
+
transition: all 0.2s;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
button:hover {
|
| 77 |
+
background: #9f8b77;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
.game-container {
|
| 81 |
+
position: relative;
|
| 82 |
+
background: #bbada0;
|
| 83 |
+
border-radius: 6px;
|
| 84 |
+
padding: 15px;
|
| 85 |
+
margin-bottom: 20px;
|
| 86 |
+
height: 470px;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
.grid-container {
|
| 90 |
+
display: grid;
|
| 91 |
+
grid-template-columns: repeat(4, 1fr);
|
| 92 |
+
grid-gap: 15px;
|
| 93 |
+
position: relative;
|
| 94 |
+
width: 100%;
|
| 95 |
+
height: 100%;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
.grid-cell {
|
| 99 |
+
background: rgba(238, 228, 218, 0.35);
|
| 100 |
+
border-radius: 3px;
|
| 101 |
+
position: relative;
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
.tile {
|
| 105 |
+
position: absolute;
|
| 106 |
+
width: calc(25% - 15px);
|
| 107 |
+
height: calc(25% - 15px);
|
| 108 |
+
display: flex;
|
| 109 |
+
justify-content: center;
|
| 110 |
+
align-items: center;
|
| 111 |
+
font-size: 36px;
|
| 112 |
+
font-weight: bold;
|
| 113 |
+
color: #776e65;
|
| 114 |
+
background: #eee4da;
|
| 115 |
+
border-radius: 3px;
|
| 116 |
+
transition: all 0.15s cubic-bezier(0.4, 0.0, 0.2, 1);
|
| 117 |
+
will-change: transform, opacity;
|
| 118 |
+
z-index: 10;
|
| 119 |
+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
.tile-2 { background: #eee4da; }
|
| 123 |
+
.tile-4 { background: #ede0c8; }
|
| 124 |
+
.tile-8 { background: #f2b179; color: white; }
|
| 125 |
+
.tile-16 { background: #f59563; color: white; }
|
| 126 |
+
.tile-32 { background: #f67c5f; color: white; }
|
| 127 |
+
.tile-64 { background: #f65e3b; color: white; }
|
| 128 |
+
.tile-128 {
|
| 129 |
+
background: #edcf72;
|
| 130 |
+
color: white;
|
| 131 |
+
font-size: 30px;
|
| 132 |
+
}
|
| 133 |
+
.tile-256 {
|
| 134 |
+
background: #edcc61;
|
| 135 |
+
color: white;
|
| 136 |
+
font-size: 30px;
|
| 137 |
+
}
|
| 138 |
+
.tile-512 {
|
| 139 |
+
background: #edc850;
|
| 140 |
+
color: white;
|
| 141 |
+
font-size: 30px;
|
| 142 |
+
}
|
| 143 |
+
.tile-1024 {
|
| 144 |
+
background: #edc53f;
|
| 145 |
+
color: white;
|
| 146 |
+
font-size: 25px;
|
| 147 |
+
}
|
| 148 |
+
.tile-2048 {
|
| 149 |
+
background: #edc22e;
|
| 150 |
+
color: white;
|
| 151 |
+
font-size: 25px;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
.game-over, .game-won {
|
| 155 |
+
position: absolute;
|
| 156 |
+
top: 0;
|
| 157 |
+
left: 0;
|
| 158 |
+
width: 100%;
|
| 159 |
+
height: 100%;
|
| 160 |
+
background: rgba(238, 228, 218, 0.73);
|
| 161 |
+
display: flex;
|
| 162 |
+
flex-direction: column;
|
| 163 |
+
align-items: center;
|
| 164 |
+
justify-content: center;
|
| 165 |
+
z-index: 100;
|
| 166 |
+
display: none;
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
.game-over p, .game-won p {
|
| 170 |
+
font-size: 60px;
|
| 171 |
+
font-weight: bold;
|
| 172 |
+
color: #776e65;
|
| 173 |
+
margin-bottom: 20px;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
.game-explanation {
|
| 177 |
+
text-align: center;
|
| 178 |
+
color: #776e65;
|
| 179 |
+
font-size: 18px;
|
| 180 |
+
line-height: 1.5;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
@keyframes appear {
|
| 184 |
+
0% {
|
| 185 |
+
opacity: 0;
|
| 186 |
+
transform: scale(0.5) rotate(0deg);
|
| 187 |
+
}
|
| 188 |
+
100% {
|
| 189 |
+
opacity: 1;
|
| 190 |
+
transform: scale(1) rotate(360deg);
|
| 191 |
+
}
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
@keyframes pop {
|
| 195 |
+
0% { transform: scale(0.8); }
|
| 196 |
+
50% { transform: scale(1.1); }
|
| 197 |
+
100% { transform: scale(1); }
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
@keyframes merge {
|
| 201 |
+
0% { transform: scale(1); }
|
| 202 |
+
50% { transform: scale(1.2); }
|
| 203 |
+
100% { transform: scale(1); }
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
.new-tile {
|
| 207 |
+
animation: appear 0.3s cubic-bezier(0.4, 0.0, 0.2, 1) forwards;
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
.merged-tile {
|
| 211 |
+
animation: merge 0.2s cubic-bezier(0.4, 0.0, 0.2, 1) forwards;
|
| 212 |
+
z-index: 20;
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
.move-tile {
|
| 216 |
+
transition: all 0.15s cubic-bezier(0.4, 0.0, 0.2, 1);
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
.merged-tile {
|
| 220 |
+
animation: pop 0.15s ease-in-out;
|
| 221 |
+
z-index: 20;
|
| 222 |
+
}
|
vercel.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": 2,
|
| 3 |
+
"name": "ai-shipment-optimization",
|
| 4 |
+
"builds": [
|
| 5 |
+
{
|
| 6 |
+
"src": "deploy.py",
|
| 7 |
+
"use": "@vercel/python"
|
| 8 |
+
}
|
| 9 |
+
],
|
| 10 |
+
"routes": [
|
| 11 |
+
{
|
| 12 |
+
"src": "/(.*)",
|
| 13 |
+
"dest": "deploy.py"
|
| 14 |
+
}
|
| 15 |
+
],
|
| 16 |
+
"env": {
|
| 17 |
+
"FLASK_ENV": "production"
|
| 18 |
+
},
|
| 19 |
+
"functions": {
|
| 20 |
+
"deploy.py": {
|
| 21 |
+
"maxDuration": 30
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
}
|