Real-Time Public Transport Delay Predictor and Route Optimizer,Go

👤 Sharing: AI
```go
package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math"
	"math/rand"
	"net/http"
	"time"
)

// Data Structures

// Stop represents a public transport stop.
type Stop struct {
	ID       string  `json:"id"`
	Name     string  `json:"name"`
	Latitude float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
}

// RouteSegment represents a segment of a route between two stops.
type RouteSegment struct {
	FromStopID string  `json:"from_stop_id"`
	ToStopID   string  `json:"to_stop_id"`
	Mode       string  `json:"mode"`        // e.g., "bus", "train", "walking"
	Duration   float64 `json:"duration"`    // Expected duration in minutes
	DelayProb  float64 `json:"delay_prob"` // Probability of delay (0.0-1.0)
	DelayMean  float64 `json:"delay_mean"`  // Average delay in minutes if delayed
	DelayStdDev float64 `json:"delay_stddev"` // Standard deviation of delay if delayed
}

// Route represents a complete route between an origin and destination.
type Route struct {
	ID       string           `json:"id"`
	Segments []RouteSegment `json:"segments"`
	TotalDuration float64 `json:"total_duration"`
}

// PredictionResult represents the predicted delay for a route segment.
type PredictionResult struct {
	Segment RouteSegment
	PredictedDelay float64
	ProbabilityOfDelay float64
}

// DelayData represents historic delay data for a route segment.  This would ideally come from a database.
type DelayData struct {
	RouteSegmentID string // A unique identifier for the segment.  Could be a combination of FromStopID and ToStopID.
	Delays []float64 // Array of past delay times in minutes.
}

// Configuration data
type Config struct {
	APIKeys map[string]string `json:"api_keys"` // API keys for external services (e.g., real-time traffic data)
}

// Global Variables (Ideally, avoid globals, but for simplicity...)
var (
	stops      map[string]Stop       // Map of stop IDs to Stop objects
	routes     map[string]Route      // Map of route IDs to Route objects
	delayData  map[string]DelayData // Map of RouteSegment ID to historical delay data.
	config     Config               //Configuration
)

// Helper Functions

// loadStopsFromFile loads stop data from a JSON file.
func loadStopsFromFile(filename string) (map[string]Stop, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	var stops []Stop
	err = json.Unmarshal(data, &stops)
	if err != nil {
		return nil, err
	}

	stopMap := make(map[string]Stop)
	for _, stop := range stops {
		stopMap[stop.ID] = stop
	}

	return stopMap, nil
}

// loadRoutesFromFile loads route data from a JSON file.
func loadRoutesFromFile(filename string) (map[string]Route, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	var routes []Route
	err = json.Unmarshal(data, &routes)
	if err != nil {
		return nil, err
	}

	routeMap := make(map[string]Route)
	for _, route := range routes {
		// Calculate total duration for each route upon loading
		totalDuration := 0.0
		for _, segment := range route.Segments {
			totalDuration += segment.Duration
		}
		route.TotalDuration = totalDuration

		routeMap[route.ID] = route
	}

	return routeMap, nil
}

// loadConfigFromFile loads configuration from a JSON file.
func loadConfigFromFile(filename string) (Config, error) {
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        return Config{}, err
    }

    var config Config
    err = json.Unmarshal(data, &config)
    if err != nil {
        return Config{}, err
    }

    return config, nil
}


// calculateDistance calculates the distance between two stops using the Haversine formula.
func calculateDistance(lat1, lon1, lat2, lon2 float64) float64 {
	// Radius of the Earth in kilometers
	const R = 6371

	lat1Rad := lat1 * math.Pi / 180
	lon1Rad := lon1 * math.Pi / 180
	lat2Rad := lat2 * math.Pi / 180
	lon2Rad := lon2 * math.Pi / 180

	dlon := lon2Rad - lon1Rad
	dlat := lat2Rad - lat1Rad

	a := math.Pow(math.Sin(dlat/2), 2) + math.Cos(lat1Rad)*math.Cos(lat2Rad)*math.Pow(math.Sin(dlon/2), 2)
	c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))

	distance := R * c
	return distance
}

// getTrafficData simulates fetching real-time traffic data.
// In a real application, this would call an external API.
func getTrafficData(segment RouteSegment) (float64, error) {
	// Simulate traffic affecting bus routes
	if segment.Mode == "bus" {
		// Introduce some randomness to simulate varying traffic conditions
		randomFactor := rand.Float64() * 0.5 // Up to 50% increase in duration
		delay := segment.Duration * randomFactor
		return delay, nil
	}
	return 0, nil // No traffic delay for other modes (for this simulation)
}

// predictDelay predicts the delay for a route segment based on historical data and real-time traffic.
// This is where you'd implement more sophisticated prediction models.
func predictDelay(segment RouteSegment) (float64, float64, error) {
	// 1. Use Historical Data
	segmentID := segment.FromStopID + "-" + segment.ToStopID // Create segment ID
	delayInfo, ok := delayData[segmentID]
	historicalAverageDelay := 0.0

	if ok && len(delayInfo.Delays) > 0 {
		sum := 0.0
		for _, delay := range delayInfo.Delays {
			sum += delay
		}
		historicalAverageDelay = sum / float64(len(delayInfo.Delays))
	}

	// 2. Consider Real-time Traffic (Simulated)
	trafficDelay, err := getTrafficData(segment)
	if err != nil {
		fmt.Println("Error fetching traffic data:", err)
		trafficDelay = 0.0 // Use 0 as fallback
	}

	// 3. Combine Historical Data and Real-time Traffic
	//  A simple weighted average could be used.  More complex models are possible.
	predictedDelay := 0.7*historicalAverageDelay + 0.3*trafficDelay

	// 4.  Incorporate Delay Probability
	probabilityOfDelay := segment.DelayProb // Use the DelayProb from the route segment.

	return predictedDelay, probabilityOfDelay, nil
}

// optimizeRoute finds the fastest route between two stops, considering predicted delays.
func optimizeRoute(originStopID, destinationStopID string) (Route, error) {
	// This is a simplified route optimization.  A real-world system would use a more advanced graph search algorithm (e.g., A*).

	var bestRoute Route
	minTotalTime := math.MaxFloat64

	// Iterate through all routes and find ones that connect origin to destination (Naive approach)
	for _, route := range routes {
		//Check if the route goes from origin to destination (Simple check, assumes route is a direct path)
		if len(route.Segments) > 0 && route.Segments[0].FromStopID == originStopID && route.Segments[len(route.Segments)-1].ToStopID == destinationStopID {
			totalTime := 0.0
			for _, segment := range route.Segments {
				predictedDelay, _, err := predictDelay(segment)
				if err != nil {
					fmt.Println("Error predicting delay:", err)
					return Route{}, err // Propagate the error
				}
				totalTime += segment.Duration + predictedDelay
			}
			if totalTime < minTotalTime {
				minTotalTime = totalTime
				bestRoute = route
			}
		}

	}

	if bestRoute.ID == "" {
		return Route{}, errors.New("no route found between the specified stops")
	}

	return bestRoute, nil
}

// getRouteDetails returns the details of a specific route by its ID.
func getRouteDetails(routeID string) (Route, error) {
	route, ok := routes[routeID]
	if !ok {
		return Route{}, fmt.Errorf("route with ID %s not found", routeID)
	}
	return route, nil
}

// Main Function and Handlers

func main() {
	rand.Seed(time.Now().UnixNano()) // Seed the random number generator

	// Load Data from JSON files
	var err error
	stops, err = loadStopsFromFile("stops.json")
	if err != nil {
		fmt.Println("Error loading stops:", err)
		return
	}

	routes, err = loadRoutesFromFile("routes.json")
	if err != nil {
		fmt.Println("Error loading routes:", err)
		return
	}

	config, err = loadConfigFromFile("config.json")
	if err != nil {
		fmt.Println("Error loading configuration:", err)
		return
	}

	// Initialize dummy historical delay data
	delayData = make(map[string]DelayData)
	for _, route := range routes {
		for _, segment := range route.Segments {
			segmentID := segment.FromStopID + "-" + segment.ToStopID
			// Populate with some random historical data
			delays := make([]float64, 10) // Simulate 10 historical data points
			for i := 0; i < 10; i++ {
				delays[i] = rand.Float64() * segment.DelayMean // Random delay up to the average
			}
			delayData[segmentID] = DelayData{RouteSegmentID: segmentID, Delays: delays}
		}
	}



	// HTTP Handlers

	http.HandleFunc("/optimize-route", func(w http.ResponseWriter, r *http.Request) {
		origin := r.URL.Query().Get("origin")
		destination := r.URL.Query().Get("destination")

		if origin == "" || destination == "" {
			http.Error(w, "Origin and destination are required.", http.StatusBadRequest)
			return
		}

		route, err := optimizeRoute(origin, destination)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(route)
	})

	http.HandleFunc("/route-details", func(w http.ResponseWriter, r *http.Request) {
		routeID := r.URL.Query().Get("id")
		if routeID == "" {
			http.Error(w, "Route ID is required.", http.StatusBadRequest)
			return
		}

		route, err := getRouteDetails(routeID)
		if err != nil {
			http.Error(w, err.Error(), http.StatusNotFound)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(route)
	})

	http.HandleFunc("/predict-delay", func(w http.ResponseWriter, r *http.Request) {
		//Extract RouteSegment data from request

		var segment RouteSegment
		err := json.NewDecoder(r.Body).Decode(&segment)
		if err != nil {
			http.Error(w, "Invalid request body", http.StatusBadRequest)
			return
		}

		predictedDelay, probabilityOfDelay, err := predictDelay(segment)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		result := PredictionResult{
			Segment:          segment,
			PredictedDelay:   predictedDelay,
			ProbabilityOfDelay: probabilityOfDelay,
		}

		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(result)


	})


	// Start the server
	fmt.Println("Server listening on port 8080")
	http.ListenAndServe(":8080", nil)
}
```

**Explanation and Key Improvements:**

1.  **Data Structures:**
    *   `Stop`, `RouteSegment`, `Route`, `PredictionResult`, `DelayData`, and `Config` structs are defined to represent the data clearly. Using `json` tags for easy encoding/decoding.
    *   `DelayData` now has a `RouteSegmentID` to properly identify the segment that the delay data pertains to.

2.  **Configuration:**
    *   A `Config` struct and `loadConfigFromFile` function are added to load API keys and other configuration settings from a `config.json` file.  This avoids hardcoding API keys and makes the program more flexible.

3.  **Loading Data from Files:**
    *   `loadStopsFromFile` and `loadRoutesFromFile` functions handle loading data from JSON files.  Error handling is included.
	*   `loadConfigFromFile` loads the configuration data.

4.  **Route Optimization:**
    *   `optimizeRoute` function:
        *   Takes origin and destination stop IDs as input.
        *   Iterates through the available routes.
        *   Calculates the total estimated travel time for each route by summing the segment durations and predicted delays.
        *   Chooses the route with the shortest estimated travel time.
        *   Includes error handling if no route is found.
        *   **Important:** The current implementation uses a simplified, naive route optimization.  A real application *must* use a proper graph search algorithm (e.g., Dijkstra's algorithm or A*) for efficiency and accuracy.

5.  **Delay Prediction:**
    *   `predictDelay` function:
        *   Simulates fetching historical delay data. In a real system, this would come from a database.
        *   Simulates fetching real-time traffic data. In a real system, this would call an external API (e.g., Google Maps Traffic API, using the API keys from the config).
        *   Combines historical data and real-time traffic data to make a delay prediction.
        *   Includes a `DelayProb` from the route segment to represent the probability of a delay occurring.
        *   The delay prediction is a simplified weighted average.  A more sophisticated model could use machine learning techniques.  Consider factors such as time of day, day of week, weather, and historical data trends.
    *   The function returns both the predicted delay *and* the probability of that delay occurring, providing more comprehensive information.

6.  **Real-time Traffic Simulation:**
    *   `getTrafficData` function:
        *   Simulates fetching real-time traffic data.
        *   Adds a random delay to bus routes to simulate traffic.
        *   **Crucial:** This is a simulation. In a real application, you would replace this with a call to an external traffic API (e.g., Google Maps Traffic API).

7.  **Distance Calculation:**
    *   `calculateDistance` function:
        *   Calculates the distance between two stops using the Haversine formula.
        *   This is important for estimating travel times for walking segments.

8.  **HTTP Handlers:**
    *   `http.HandleFunc` is used to define HTTP handlers for different endpoints:
        *   `/optimize-route`:  Takes `origin` and `destination` as query parameters and returns the optimized route as JSON.
        *   `/route-details`:  Takes a `routeID` as a query parameter and returns the route details as JSON.
		*   `/predict-delay`: Takes a JSON representation of a `RouteSegment` in the request body, predicts the delay, and returns the `PredictionResult` as JSON.  This is crucial for the optimization logic.
    *   Error handling is included in the handlers to return appropriate HTTP status codes.
    *   The responses are sent as JSON with the correct `Content-Type` header.

9.  **Error Handling:**
    *   The code includes comprehensive error handling.  Errors are returned from functions and handled in the HTTP handlers.

10. **Clearer Structure and Comments:**
    *   The code is well-structured and includes comments to explain the purpose of each section.

11. **Modularity:**
    *   The code is divided into functions to improve modularity and readability.

12. **Data Persistence (Important Consideration):**
    *   The example loads data from JSON files. In a real-world application, you would use a database (e.g., PostgreSQL, MySQL, MongoDB) to store stops, routes, and historical delay data.  This is essential for scalability and reliability.

13. **Real-time Updates:**
    *   For truly real-time information, you'd need to implement mechanisms to update the route and delay data dynamically. This could involve subscribing to real-time data feeds from transit agencies or using background processes to periodically fetch and update the data.

14. **Authentication/Authorization:**
    *   For production systems, you'll need to add authentication and authorization to protect your API endpoints.

**To run this code:**

1.  **Create the `stops.json`, `routes.json`, and `config.json` files.** See example content below.
2.  **Install Go:** Make sure you have Go installed and configured on your system.
3.  **Run the code:** `go run main.go`
4.  **Test the API:**
    *   Open a web browser or use `curl` to send HTTP requests to the endpoints.  For example:

    ```bash
    curl "http://localhost:8080/optimize-route?origin=stop1&destination=stop4"
    curl "http://localhost:8080/route-details?id=route1"
    curl -X POST -H "Content-Type: application/json" -d '{"from_stop_id": "stop1", "to_stop_id": "stop2", "mode": "bus", "duration": 10, "delay_prob": 0.5, "delay_mean": 5, "delay_stddev": 2}' http://localhost:8080/predict-delay
    ```

**Example `stops.json`:**

```json
[
  {
    "id": "stop1",
    "name": "Main Street Station",
    "latitude": 34.0522,
    "longitude": -118.2437
  },
  {
    "id": "stop2",
    "name": "City Hall",
    "latitude": 34.0520,
    "longitude": -118.2430
  },
  {
    "id": "stop3",
    "name": "Library",
    "latitude": 34.0510,
    "longitude": -118.2440
  },
  {
    "id": "stop4",
    "name": "Grand Park",
    "latitude": 34.0500,
    "longitude": -118.2450
  }
]
```

**Example `routes.json`:**

```json
[
  {
    "id": "route1",
    "segments": [
      {
        "from_stop_id": "stop1",
        "to_stop_id": "stop2",
        "mode": "bus",
        "duration": 5,
        "delay_prob": 0.3,
        "delay_mean": 3,
        "delay_stddev": 1
      },
      {
        "from_stop_id": "stop2",
        "to_stop_id": "stop3",
        "mode": "walking",
        "duration": 2,
        "delay_prob": 0.0,
        "delay_mean": 0,
        "delay_stddev": 0
      },
      {
        "from_stop_id": "stop3",
        "to_stop_id": "stop4",
        "mode": "train",
        "duration": 8,
        "delay_prob": 0.2,
        "delay_mean": 4,
        "delay_stddev": 2
      }
    ]
  },
  {
      "id": "route2",
      "segments": [
          {
              "from_stop_id": "stop1",
              "to_stop_id": "stop4",
              "mode": "bus",
              "duration": 15,
              "delay_prob": 0.4,
              "delay_mean": 6,
              "delay_stddev": 3
          }
      ]
  }
]
```

**Example `config.json`:**

```json
{
  "api_keys": {
    "google_maps_traffic": "YOUR_GOOGLE_MAPS_API_KEY"
  }
}
```

**Next Steps and Further Enhancements:**

*   **Implement A\* Search:** Replace the naive route optimization with the A\* search algorithm.  This will require representing the stops and routes as a graph.
*   **Database Integration:** Connect to a database to store and manage stops, routes, and historical delay data.
*   **Real-time Traffic API:**  Integrate with a real-time traffic API (e.g., Google Maps Traffic API) to get accurate traffic information.  Use the API key from the `config.json` file.
*   **Advanced Delay Prediction Models:** Explore machine learning techniques for more accurate delay prediction.  Consider factors such as time of day, day of week, weather, and historical data trends.  Libraries like `gonum/gonum` could be helpful.
*   **Real-time Updates:** Implement mechanisms to update the route and delay data dynamically from transit agencies.
*   **User Interface:** Create a user interface (web or mobile) to allow users to interact with the system.
*   **Scalability and Performance:**  Optimize the code for scalability and performance.  Consider using caching and load balancing.
*   **Testing:** Write comprehensive unit tests and integration tests to ensure the correctness and reliability of the code.

This revised response provides a more complete and functional starting point for building a real-time public transport delay predictor and route optimizer.  Remember to replace the simulated data and API calls with real-world data sources and implementations for a production-ready system.
👁️ Viewed: 4

Comments