| import gradio as gr |
|
|
| |
| 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, |
| row_count=(0, "dynamic"), |
| col_count=(0, "dynamic") |
| ), |
| 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" |
| ) |
|
|
|
|
| |
| with gr.Blocks() as markdown_tab: |
| gr.HTML(HTML_INTRODUCTION) |
|
|
|
|
| |
| 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 |
|
|
| |
|
|
| 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 = list(named_interfaces.keys()) |
| interface_list = list(named_interfaces.values()) |
|
|
|
|
| |
| gradio_server = gr.TabbedInterface( |
| interface_list, |
| tab_names=tab_names, |
| title="🏁 Formula 1 MCP server 🏎️" |
| ) |
|
|
| |
| if __name__ == "__main__": |
| gradio_server.launch(mcp_server=True) |