|
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) |