File size: 9,445 Bytes
014f597
1d0b9d1
89c9126
35aeee0
655dcc9
89c9126
44e58a6
 
c6542ed
6269c32
655dcc9
 
 
89c9126
 
6bdfadb
35aeee0
6bdfadb
 
44e58a6
6bdfadb
89c9126
18c04d1
 
44e58a6
 
 
35aeee0
44e58a6
 
 
 
 
18c04d1
 
89c9126
 
6bdfadb
35aeee0
89c9126
 
18c04d1
b139634
89c9126
1d0b9d1
89c9126
18c04d1
014f597
 
6bdfadb
35aeee0
89c9126
 
 
 
 
18c04d1
89c9126
 
6bdfadb
35aeee0
6bdfadb
 
18c04d1
 
 
6bdfadb
 
b139634
18c04d1
6bdfadb
 
c6542ed
35aeee0
c6542ed
 
18c04d1
 
c6542ed
18c04d1
 
 
 
 
c6542ed
18c04d1
c6542ed
 
6269c32
35aeee0
6269c32
 
 
 
 
18c04d1
6269c32
6bdfadb
95e43e2
 
 
 
 
 
 
18c04d1
95e43e2
d07810d
d69ce5a
95e43e2
 
 
655dcc9
 
 
 
 
 
 
 
 
 
1d33ca6
655dcc9
1d33ca6
655dcc9
 
 
 
1d33ca6
655dcc9
1d33ca6
655dcc9
 
 
 
1d33ca6
655dcc9
1d33ca6
655dcc9
 
 
 
1d33ca6
655dcc9
1d33ca6
655dcc9
 
 
 
 
 
1d33ca6
655dcc9
1d33ca6
655dcc9
 
 
 
 
1d33ca6
655dcc9
 
 
1d33ca6
655dcc9
 
 
 
 
 
1d33ca6
655dcc9
 
 
 
1d33ca6
655dcc9
 
 
d69ce5a
6bdfadb
97a44d4
b139634
44e58a6
b139634
 
c6542ed
6269c32
97a44d4
95e43e2
655dcc9
6bdfadb
89c9126
b139634
 
 
89c9126
 
 
1d0b9d1
89c9126
 
97a44d4
1d0b9d1
014f597
1d0b9d1
014f597
1d0b9d1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
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,
    MARKDOWN_OPENF1_EXAMPLES,
    OPENF1_TOOL_DESCRIPTION
)

iface_driver_championship_standings = gr.Interface(
    fn=fastf1_tools.driver_championship_standings,
    inputs=[
        gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR),
        gr.Dropdown(label="Driver", choices=DRIVER_NAMES)
    ],
    outputs="text",
    title="World Driver Championship Standings",
    description="Get the world driver championship standings for a specific driver"
)

iface_constructor_championship_standings = gr.Interface(
    fn=fastf1_tools.constructor_championship_standings,
    inputs=[
        gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR),
        gr.Dropdown(label="Constructor", choices=CONSTRUCTOR_NAMES)
    ],
    outputs="text",
    title="World Constructor Championship Standings",
    description="Get the world constructor championship standings for a specific constructor"
)

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")
    ],
    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"),
        gr.Dropdown(label="Driver", choices=DRIVER_NAMES, info="Only applied for speed visualization. gear uses fastest lap during race.")
    ],
    outputs="image",
    title="Track Visualizations",
    description="Get the track visualization for the given Grand Prix. Example: (2025,Monaco,speed,Leclerc)"
)

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

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


# Create your markdown-only tab using Blocks
with gr.Blocks() as markdown_tab:
    gr.Markdown(MARKDOWN_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()
            def _get_api_endpoints():
                return openf1_tools.get_api_endpoints()
            btn.click(_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()
            def _get_api_endpoint(endpoint):
                return openf1_tools.get_api_endpoint(endpoint)
            btn.click(_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()
            def _get_endpoint_info(endpoint):
                return openf1_tools.get_endpoint_info(endpoint)
            btn.click(_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()
            def _get_filter_info(filter_name):
                return openf1_tools.get_filter_info(filter_name)
            btn.click(_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&")
            def _get_filter_string(filter_name, filter_value, operator):
                return openf1_tools.get_filter_string(filter_name, filter_value, operator)
            btn.click(_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")
            def _apply_filters(api_string, filters):
                # Expect filters as comma-separated
                filter_list = [f.strip() for f in filters.split(",") if f.strip()]
                return openf1_tools.apply_filters(api_string, *filter_list)
            btn.click(_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()
            def _send_request(api_string):
                try:
                    return openf1_tools.send_request(api_string)
                except Exception as e:
                    return {"error": str(e)}
            btn.click(_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)