import gradio as gr from nyct_gtfs import NYCTFeed from datetime import datetime from typing import Any # Helper function to convert datetime objects to string def convert_datetime_to_string(datetime_obj: Any) -> str | None: if datetime_obj is None: return None return datetime_obj.strftime("%H:%M:%S") # Helper function to process train data from NYCTFeed def get_train_info_list(trains_data: Any) -> list[dict[str, Any]]: train_info_list_data = [] for train in trains_data: train_info = { "name": str(train), "line": train.route_id, "direction": train.direction, "stop_time_updates": [], } train_info["stop_time_updates"] = [ {"stop_name": x.stop_name, "arrival": convert_datetime_to_string(x.arrival)} for x in train.stop_time_updates ] train_info_list_data.append(train_info) return train_info_list_data def get_next_mta_train( target_station: str, target_direction: str, feed_id: str = "1" ) -> str: """Get the next train arrival information for a given station and direction. Args: target_station: The name of the target station (e.g., "Times Sq-42 St", "14 St-Union Sq"). target_direction: The direction of the train ("N" for Northbound / Uptown, "S" for Southbound / Downtown). feed_id: The GTFS feed ID for the subway lines (e.g., "1" for 1,2,3,4,5,6,S lines). Common Feed IDs: "1": 1, 2, 3, 4, 5, 6, 7, S (42 St Shuttle) "A": A, C, E, S (Rockaway Shuttle) "N": N, Q, R, W "B": B, D, F, M, S (Franklin Ave) "L": L "G": G "J": J, Z "7": 7 "SIR": Staten Island Railway This function returns a string with the next train arrival information for the given station and direction. You can use this tool to get the next train arrival information for a given station and direction. """ try: feed = NYCTFeed(feed_id) trains_data = feed.trips except Exception as e: return f"Failed to load MTA feed data for feed ID {feed_id}: {e}" if not trains_data: return f"No train data found for feed ID {feed_id}." train_info_processed = get_train_info_list(trains_data) current_time = datetime.now().strftime("%H:%M:%S") train_info_string = f"Current time: {current_time}\n" for train in train_info_processed: for stop in train["stop_time_updates"]: if ( stop["stop_name"] == target_station and train["direction"] == target_direction ): # train_name = train["name"] # Original notebook had this, but it's often complex like "14:50 S 1 to South Ferry" train_line = train["line"] # train_direction = train["direction"] # Already have target_direction train_arrival = stop["arrival"] if train_arrival: train_info_string += f"The next {target_direction} bound {train_line} train arriving at {target_station} will arrive at {train_arrival}.\n" else: train_info_string += f"The next {target_direction} bound {train_line} train is scheduled at {target_station}, but arrival time is not currently available.\n" if train_info_string == "": return f"No {target_direction} bound trains found for {target_station} on feed {feed_id} at this time." return train_info_string demo = gr.Interface( fn=get_next_mta_train, inputs=["text", "text", "text"], outputs="text", title="MTA Subway Tracker", description="Get the next train arrival information for a given station and direction", ) demo.launch(mcp_server=True)