import gradio as gr # Local modules import fastf1_tools import openf1_tools from utils.constants import ( DRIVER_NAMES, CONSTRUCTOR_NAMES, CURRENT_YEAR, DROPDOWN_SESSION_TYPES, MARKDOWN_INTRODUCTION, HTML_INTRODUCTION, MARKDOWN_OPENF1_EXAMPLES, OPENF1_TOOL_DESCRIPTION, CONSTRUCTORS_PER_SEASON, DRIVERS_PER_SEASON ) with gr.Blocks() as iface_driver_championship_standings: gr.Markdown("## World Driver Championship Standings\nGet the world driver championship standings for a specific driver. Note that the older data has gaps and may not be entirely complete.") with gr.Row(): year_input = gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR) driver_dropdown = gr.Dropdown(label="Driver", choices=DRIVERS_PER_SEASON.get(str(year_input.value), [])) output_text = gr.Textbox(label="Result") submit_btn = gr.Button("Submit") def update_drivers(year): choices = DRIVERS_PER_SEASON.get(str(year), []) return gr.update(choices=choices, value=(choices[0] if choices else None)) year_input.blur( update_drivers, inputs=year_input, outputs=driver_dropdown ) submit_btn.click( fastf1_tools.driver_championship_standings, inputs=[year_input, driver_dropdown], outputs=output_text ) with gr.Blocks() as iface_constructor_championship_standings: gr.Markdown("## World Constructor Championship Standings\nGet the current/past world constructor championship standings for a specific constructor. Note that the older data has gaps and may not be entirely complete.") with gr.Row(): year_input = gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR) constructor_dropdown = gr.Dropdown(label="Constructor", choices=CONSTRUCTORS_PER_SEASON.get(str(year_input.value), [])) output_text = gr.Textbox(label="Result") submit_btn = gr.Button("Submit") def update_constructors(year): choices = CONSTRUCTORS_PER_SEASON.get(str(year), []) return gr.update(choices=choices, value=(choices[0] if choices else None)) year_input.blur( update_constructors, inputs=year_input, outputs=constructor_dropdown ) submit_btn.click( fastf1_tools.constructor_championship_standings, inputs=[year_input, constructor_dropdown], outputs=output_text ) iface_event_info = gr.Interface( fn=fastf1_tools.get_event_info, inputs=[ gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR), gr.Textbox(label="Grand Prix", placeholder="Ex: Monaco", info="The name of the GP/country/location (Fuzzy matching supported) or round number"), gr.Radio(["human", "LLM"], label="Display format", value="human", info="Toggle between human-readable (parsed) and LLM output (raw)") ], outputs="text", title="Event Info", description="Get information about a specific Grand Prix event. Example: (2025,Monaco,human)" ) iface_season_calendar = gr.Interface( fn=fastf1_tools.get_season_calendar, inputs=[ gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR), ], outputs="text", title="Season Calendar", description="Get the season calendar for the given year" ) iface_track_visualization = gr.Interface( fn=fastf1_tools.track_visualization, inputs=[ gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR), gr.Textbox(label="Grand Prix", placeholder="Ex: Monaco", info="The name of the GP/country/location (Fuzzy matching supported) or round number"), gr.Radio(["speed", "corners", "gear"], label="Visualization type", value="speed", info="What type of track visualization to generate"), ], outputs="image", title="Track Visualizations", description="Get the track visualization (speed/corners/gear) for the fastest lap at the specific Grand Prix race. Example: (2025,Monaco,speed)" ) iface_session_results = gr.Interface( fn=fastf1_tools.get_session_results, inputs=[ gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR), gr.Textbox(label="Grand Prix", placeholder="Ex: Monaco", info="The name of the GP/country/location (Fuzzy matching supported) or round number"), gr.Dropdown([session_type for session_type in DROPDOWN_SESSION_TYPES if "practice" not in session_type], label="Session type", value="race", info="The session type to get results for. Dataframe's columns vary depending on session type.") ], outputs=gr.Dataframe( headers=None, # Let it infer from returned DataFrame row_count=(0, "dynamic"), # Start empty, allow it to grow col_count=(0, "dynamic") # Let columns adjust too ), title="Session Results", description="Get the session results for the given Grand Prix. Example: (2025,Monaco,qualifying)" ) iface_driver_info = gr.Interface( fn=fastf1_tools.get_driver_info, inputs=[ gr.Dropdown(label="Driver", choices=DRIVER_NAMES) ], outputs="text", title="Driver Info", description="Get background information about a specific driver from the 2025 Formula 1 season" ) iface_constructor_info = gr.Interface( fn=fastf1_tools.get_constructor_info, inputs=[ gr.Dropdown(label="Constructor", choices=CONSTRUCTOR_NAMES) ], outputs="text", title="Constructor Info", description="Get background information about a specific constructor from the 2025 Formula 1 season" ) # About introduction tab with gr.Blocks() as markdown_tab: gr.HTML(HTML_INTRODUCTION) # OpenF1 tools tab def openf1_tools_tab(): with gr.Blocks() as openf1_tools_tab: gr.Markdown(OPENF1_TOOL_DESCRIPTION) with gr.Accordion("get_api_endpoints()", open=False): btn = gr.Button("Get all endpoints") output = gr.JSON() btn.click(openf1_tools.get_api_endpoints, outputs=output) with gr.Accordion("get_api_endpoint(endpoint)", open=False): endpoint_in = gr.Textbox(label="Endpoint", placeholder="e.g. sessions") btn = gr.Button("Get endpoint info") output = gr.JSON() btn.click(openf1_tools.get_api_endpoint, inputs=endpoint_in, outputs=output) with gr.Accordion("get_endpoint_info(endpoint)", open=False): endpoint_in = gr.Textbox(label="Endpoint", placeholder="e.g. sessions") btn = gr.Button("Get endpoint details") output = gr.JSON() btn.click(openf1_tools.get_endpoint_info, inputs=endpoint_in, outputs=output) with gr.Accordion("get_filter_info(filter_name)", open=False): filter_in = gr.Textbox(label="Filter name", placeholder="e.g. driver_number") btn = gr.Button("Get filter info") output = gr.JSON() btn.click(openf1_tools.get_filter_info, inputs=filter_in, outputs=output) with gr.Accordion("get_filter_string(filter_name, filter_value, operator)", open=False): filter_name = gr.Textbox(label="Filter name", placeholder="e.g. driver_number") filter_value = gr.Textbox(label="Filter value", placeholder="e.g. 16") operator = gr.Dropdown(label="Operator", choices=["=", ">", "<", ">=", "<="], value="=") btn = gr.Button("Get filter string") output = gr.Textbox(label="Filter string", info="Example: driver_number=16&") btn.click(openf1_tools.get_filter_string, inputs=[filter_name, filter_value, operator], outputs=output) with gr.Accordion("apply_filters(api_string, *filters)", open=False): api_string = gr.Textbox(label="Base API string", placeholder="e.g. https://api.openf1.org/v1/sessions?") filters = gr.Textbox(label="Filters (comma-separated)", placeholder="e.g. driver_number=16&,session_key=123&") btn = gr.Button("Apply filters") output = gr.Textbox(label="Full API string") btn.click(openf1_tools.apply_filters, inputs=[api_string, filters], outputs=output) with gr.Accordion("send_request(api_string)", open=False): with gr.Accordion("Example API requests (copy & paste into text box below)", open=False): gr.Markdown(MARKDOWN_OPENF1_EXAMPLES) api_string = gr.Textbox(label="Full API string", placeholder="e.g. https://api.openf1.org/v1/sessions?driver_number=16") btn = gr.Button("Send API request") output = gr.JSON() btn.click(openf1_tools.send_request, inputs=api_string, outputs=output) return openf1_tools_tab # OpenF1 tabs named_interfaces = { "About": markdown_tab, "Driver Championship Standings": iface_driver_championship_standings, "Constructor Championship Standings": iface_constructor_championship_standings, "Event Info": iface_event_info, "Season Calendar": iface_season_calendar, "Track Visualizations": iface_track_visualization, "Session Results": iface_session_results, "Driver Info": iface_driver_info, "Constructor Info": iface_constructor_info, "OpenF1 Tools": openf1_tools_tab() } # Tab names and interfaces tab_names = list(named_interfaces.keys()) interface_list = list(named_interfaces.values()) # Combine all the interfaces into a single TabbedInterface gradio_server = gr.TabbedInterface( interface_list, tab_names=tab_names, title="🏁 Formula 1 MCP server 🏎️" ) # Launch the interface and MCP server if __name__ == "__main__": gradio_server.launch(mcp_server=True)