Spaces:
Sleeping
Sleeping
driver live standings
Browse files- api_playground.ipynb +122 -1
- app.py +10 -10
- tools.py +29 -28
api_playground.ipynb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
"cells": [
|
| 3 |
{
|
| 4 |
"cell_type": "code",
|
| 5 |
-
"execution_count":
|
| 6 |
"id": "b7d2515e",
|
| 7 |
"metadata": {},
|
| 8 |
"outputs": [
|
|
@@ -264,6 +264,127 @@
|
|
| 264 |
"print(event2.keys())\n"
|
| 265 |
]
|
| 266 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
{
|
| 268 |
"cell_type": "code",
|
| 269 |
"execution_count": 2,
|
|
|
|
| 2 |
"cells": [
|
| 3 |
{
|
| 4 |
"cell_type": "code",
|
| 5 |
+
"execution_count": 2,
|
| 6 |
"id": "b7d2515e",
|
| 7 |
"metadata": {},
|
| 8 |
"outputs": [
|
|
|
|
| 264 |
"print(event2.keys())\n"
|
| 265 |
]
|
| 266 |
},
|
| 267 |
+
{
|
| 268 |
+
"cell_type": "code",
|
| 269 |
+
"execution_count": 24,
|
| 270 |
+
"id": "e6de8707",
|
| 271 |
+
"metadata": {},
|
| 272 |
+
"outputs": [
|
| 273 |
+
{
|
| 274 |
+
"data": {
|
| 275 |
+
"text/html": [
|
| 276 |
+
"<div>\n",
|
| 277 |
+
"<style scoped>\n",
|
| 278 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 279 |
+
" vertical-align: middle;\n",
|
| 280 |
+
" }\n",
|
| 281 |
+
"\n",
|
| 282 |
+
" .dataframe tbody tr th {\n",
|
| 283 |
+
" vertical-align: top;\n",
|
| 284 |
+
" }\n",
|
| 285 |
+
"\n",
|
| 286 |
+
" .dataframe thead th {\n",
|
| 287 |
+
" text-align: right;\n",
|
| 288 |
+
" }\n",
|
| 289 |
+
"</style>\n",
|
| 290 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 291 |
+
" <thead>\n",
|
| 292 |
+
" <tr style=\"text-align: right;\">\n",
|
| 293 |
+
" <th></th>\n",
|
| 294 |
+
" <th>position</th>\n",
|
| 295 |
+
" <th>positionText</th>\n",
|
| 296 |
+
" <th>points</th>\n",
|
| 297 |
+
" <th>wins</th>\n",
|
| 298 |
+
" <th>driverId</th>\n",
|
| 299 |
+
" <th>driverNumber</th>\n",
|
| 300 |
+
" <th>driverCode</th>\n",
|
| 301 |
+
" <th>driverUrl</th>\n",
|
| 302 |
+
" <th>givenName</th>\n",
|
| 303 |
+
" <th>familyName</th>\n",
|
| 304 |
+
" <th>dateOfBirth</th>\n",
|
| 305 |
+
" <th>driverNationality</th>\n",
|
| 306 |
+
" <th>constructorIds</th>\n",
|
| 307 |
+
" <th>constructorUrls</th>\n",
|
| 308 |
+
" <th>constructorNames</th>\n",
|
| 309 |
+
" <th>constructorNationalities</th>\n",
|
| 310 |
+
" </tr>\n",
|
| 311 |
+
" </thead>\n",
|
| 312 |
+
" <tbody>\n",
|
| 313 |
+
" <tr>\n",
|
| 314 |
+
" <th>0</th>\n",
|
| 315 |
+
" <td>1</td>\n",
|
| 316 |
+
" <td>1</td>\n",
|
| 317 |
+
" <td>575.0</td>\n",
|
| 318 |
+
" <td>19</td>\n",
|
| 319 |
+
" <td>max_verstappen</td>\n",
|
| 320 |
+
" <td>33</td>\n",
|
| 321 |
+
" <td>VER</td>\n",
|
| 322 |
+
" <td>http://en.wikipedia.org/wiki/Max_Verstappen</td>\n",
|
| 323 |
+
" <td>Max</td>\n",
|
| 324 |
+
" <td>Verstappen</td>\n",
|
| 325 |
+
" <td>1997-09-30</td>\n",
|
| 326 |
+
" <td>Dutch</td>\n",
|
| 327 |
+
" <td>[red_bull]</td>\n",
|
| 328 |
+
" <td>[http://en.wikipedia.org/wiki/Red_Bull_Racing]</td>\n",
|
| 329 |
+
" <td>[Red Bull]</td>\n",
|
| 330 |
+
" <td>[Austrian]</td>\n",
|
| 331 |
+
" </tr>\n",
|
| 332 |
+
" <tr>\n",
|
| 333 |
+
" <th>1</th>\n",
|
| 334 |
+
" <td>2</td>\n",
|
| 335 |
+
" <td>2</td>\n",
|
| 336 |
+
" <td>285.0</td>\n",
|
| 337 |
+
" <td>2</td>\n",
|
| 338 |
+
" <td>perez</td>\n",
|
| 339 |
+
" <td>11</td>\n",
|
| 340 |
+
" <td>PER</td>\n",
|
| 341 |
+
" <td>http://en.wikipedia.org/wiki/Sergio_P%C3%A9rez</td>\n",
|
| 342 |
+
" <td>Sergio</td>\n",
|
| 343 |
+
" <td>Pérez</td>\n",
|
| 344 |
+
" <td>1990-01-26</td>\n",
|
| 345 |
+
" <td>Mexican</td>\n",
|
| 346 |
+
" <td>[red_bull]</td>\n",
|
| 347 |
+
" <td>[http://en.wikipedia.org/wiki/Red_Bull_Racing]</td>\n",
|
| 348 |
+
" <td>[Red Bull]</td>\n",
|
| 349 |
+
" <td>[Austrian]</td>\n",
|
| 350 |
+
" </tr>\n",
|
| 351 |
+
" </tbody>\n",
|
| 352 |
+
"</table>\n",
|
| 353 |
+
"</div>"
|
| 354 |
+
],
|
| 355 |
+
"text/plain": [
|
| 356 |
+
" position positionText points wins driverId driverNumber \\\n",
|
| 357 |
+
"0 1 1 575.0 19 max_verstappen 33 \n",
|
| 358 |
+
"1 2 2 285.0 2 perez 11 \n",
|
| 359 |
+
"\n",
|
| 360 |
+
" driverCode driverUrl givenName \\\n",
|
| 361 |
+
"0 VER http://en.wikipedia.org/wiki/Max_Verstappen Max \n",
|
| 362 |
+
"1 PER http://en.wikipedia.org/wiki/Sergio_P%C3%A9rez Sergio \n",
|
| 363 |
+
"\n",
|
| 364 |
+
" familyName dateOfBirth driverNationality constructorIds \\\n",
|
| 365 |
+
"0 Verstappen 1997-09-30 Dutch [red_bull] \n",
|
| 366 |
+
"1 Pérez 1990-01-26 Mexican [red_bull] \n",
|
| 367 |
+
"\n",
|
| 368 |
+
" constructorUrls constructorNames \\\n",
|
| 369 |
+
"0 [http://en.wikipedia.org/wiki/Red_Bull_Racing] [Red Bull] \n",
|
| 370 |
+
"1 [http://en.wikipedia.org/wiki/Red_Bull_Racing] [Red Bull] \n",
|
| 371 |
+
"\n",
|
| 372 |
+
" constructorNationalities \n",
|
| 373 |
+
"0 [Austrian] \n",
|
| 374 |
+
"1 [Austrian] "
|
| 375 |
+
]
|
| 376 |
+
},
|
| 377 |
+
"execution_count": 24,
|
| 378 |
+
"metadata": {},
|
| 379 |
+
"output_type": "execute_result"
|
| 380 |
+
}
|
| 381 |
+
],
|
| 382 |
+
"source": [
|
| 383 |
+
"ergastandings = fastf1.ergast.Ergast()\n",
|
| 384 |
+
"driver_standings = ergastandings.get_driver_standings(2023).content[0]\n",
|
| 385 |
+
"driver_standings.head(2)"
|
| 386 |
+
]
|
| 387 |
+
},
|
| 388 |
{
|
| 389 |
"cell_type": "code",
|
| 390 |
"execution_count": 2,
|
app.py
CHANGED
|
@@ -22,7 +22,7 @@ with open("assets/constructor_details.json") as f:
|
|
| 22 |
|
| 23 |
|
| 24 |
iface_driver_championship_standings = gr.Interface(
|
| 25 |
-
fn=tools.
|
| 26 |
inputs=[
|
| 27 |
gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR),
|
| 28 |
gr.Dropdown(driver_names)
|
|
@@ -37,7 +37,7 @@ iface_event_info = gr.Interface(
|
|
| 37 |
inputs=[
|
| 38 |
gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR),
|
| 39 |
gr.Textbox(label="Grand Prix", placeholder="Ex: Monaco", info="The name of the GP/country/location (Fuzzy matching supported)"),
|
| 40 |
-
gr.Radio(["human", "LLM"], label="
|
| 41 |
],
|
| 42 |
outputs="text",
|
| 43 |
title="Event Info",
|
|
@@ -63,21 +63,21 @@ iface_track_visualization = gr.Interface(
|
|
| 63 |
gr.Dropdown(driver_names)
|
| 64 |
],
|
| 65 |
outputs="image",
|
| 66 |
-
title="
|
| 67 |
description="Get the track visualization for the given Grand Prix"
|
| 68 |
)
|
| 69 |
|
| 70 |
|
| 71 |
-
# TODO swap to this format
|
| 72 |
named_interfaces = {
|
| 73 |
-
"
|
| 74 |
-
"
|
| 75 |
-
"
|
| 76 |
-
"
|
| 77 |
}
|
| 78 |
|
| 79 |
-
|
| 80 |
-
tab_names =
|
|
|
|
| 81 |
|
| 82 |
|
| 83 |
# Combine all the interfaces into a single TabbedInterface
|
|
|
|
| 22 |
|
| 23 |
|
| 24 |
iface_driver_championship_standings = gr.Interface(
|
| 25 |
+
fn=tools.driver_championship_standings,
|
| 26 |
inputs=[
|
| 27 |
gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR),
|
| 28 |
gr.Dropdown(driver_names)
|
|
|
|
| 37 |
inputs=[
|
| 38 |
gr.Number(label="Calendar year", value=CURRENT_YEAR, minimum=1950, maximum=CURRENT_YEAR),
|
| 39 |
gr.Textbox(label="Grand Prix", placeholder="Ex: Monaco", info="The name of the GP/country/location (Fuzzy matching supported)"),
|
| 40 |
+
gr.Radio(["human", "LLM"], label="Display format", value="human")
|
| 41 |
],
|
| 42 |
outputs="text",
|
| 43 |
title="Event Info",
|
|
|
|
| 63 |
gr.Dropdown(driver_names)
|
| 64 |
],
|
| 65 |
outputs="image",
|
| 66 |
+
title="Track Visualizations",
|
| 67 |
description="Get the track visualization for the given Grand Prix"
|
| 68 |
)
|
| 69 |
|
| 70 |
|
|
|
|
| 71 |
named_interfaces = {
|
| 72 |
+
"Driver Championship Standings": iface_driver_championship_standings,
|
| 73 |
+
"Event Info": iface_event_info,
|
| 74 |
+
"Season Calendar": iface_season_calendar,
|
| 75 |
+
"Track Visualizations": iface_track_visualization
|
| 76 |
}
|
| 77 |
|
| 78 |
+
# Tab names and interfaces
|
| 79 |
+
tab_names = list(named_interfaces.keys())
|
| 80 |
+
interface_list = list(named_interfaces.values())
|
| 81 |
|
| 82 |
|
| 83 |
# Combine all the interfaces into a single TabbedInterface
|
tools.py
CHANGED
|
@@ -6,34 +6,27 @@ Tools to implement
|
|
| 6 |
- driver info
|
| 7 |
- championship standings
|
| 8 |
- driver standings
|
|
|
|
| 9 |
- compare drivers
|
| 10 |
|
| 11 |
"""
|
| 12 |
|
| 13 |
-
|
| 14 |
-
## Here we implement the MCP tools
|
| 15 |
import fastf1
|
| 16 |
-
from
|
| 17 |
-
|
| 18 |
-
from fastf1.core import Session
|
| 19 |
from typing import Union
|
|
|
|
| 20 |
|
|
|
|
| 21 |
from utils import parser_utils, track_utils
|
| 22 |
-
from
|
| 23 |
|
| 24 |
# Custom types
|
| 25 |
gp = Union[str, int]
|
| 26 |
session_type = Union[str, int, None]
|
| 27 |
|
| 28 |
-
def get_season_calendar(year: int) -> str:
|
| 29 |
-
""" Returns the season calendar for the given year """
|
| 30 |
-
season_calendar = fastf1.get_event_schedule(year)
|
| 31 |
-
return parser_utils.parse_season_calendar(season_calendar)
|
| 32 |
-
|
| 33 |
def get_session(year: int, round: gp, session_type: session_type) -> Session:
|
| 34 |
-
"""
|
| 35 |
-
Returns a session specified by year, round and session type
|
| 36 |
-
"""
|
| 37 |
|
| 38 |
# Check if session type is valid
|
| 39 |
if isinstance(session_type, str):
|
|
@@ -42,6 +35,11 @@ def get_session(year: int, round: gp, session_type: session_type) -> Session:
|
|
| 42 |
|
| 43 |
return fastf1.get_session(year, round, session_type)
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
def get_event_info(year: int, round: gp, format: str) -> str:
|
| 46 |
""" Returns the event info for the specified session """
|
| 47 |
|
|
@@ -57,24 +55,27 @@ def get_event_info(year: int, round: gp, format: str) -> str:
|
|
| 57 |
def get_constructor_standings(year: int) -> str:
|
| 58 |
pass
|
| 59 |
|
| 60 |
-
def
|
| 61 |
pass
|
| 62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
-
def driver_position(driver_name: str) -> str:
|
| 65 |
-
"""
|
| 66 |
-
Get the current position of the given driver.
|
| 67 |
-
|
| 68 |
-
Args:
|
| 69 |
-
driver_name (str): The driver's name
|
| 70 |
-
|
| 71 |
-
Returns:
|
| 72 |
-
str: The driver's current position
|
| 73 |
-
"""
|
| 74 |
-
return f"Driver {driver_name} is in position {random.randint(1, 20)}"
|
| 75 |
|
| 76 |
-
def driver_championship_score(year: int, driver_name: str) -> str:
|
| 77 |
-
pass
|
| 78 |
|
| 79 |
def track_visualization(year: int, round: gp, visualization_type: str, driver_name: str) -> Image:
|
| 80 |
|
|
|
|
| 6 |
- driver info
|
| 7 |
- championship standings
|
| 8 |
- driver standings
|
| 9 |
+
- constructor standings
|
| 10 |
- compare drivers
|
| 11 |
|
| 12 |
"""
|
| 13 |
|
| 14 |
+
import json
|
|
|
|
| 15 |
import fastf1
|
| 16 |
+
from PIL import Image
|
|
|
|
|
|
|
| 17 |
from typing import Union
|
| 18 |
+
from fastf1.core import Session
|
| 19 |
|
| 20 |
+
# Local modules
|
| 21 |
from utils import parser_utils, track_utils
|
| 22 |
+
from utils.constants import AVAILABLE_SESSION_TYPES
|
| 23 |
|
| 24 |
# Custom types
|
| 25 |
gp = Union[str, int]
|
| 26 |
session_type = Union[str, int, None]
|
| 27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
def get_session(year: int, round: gp, session_type: session_type) -> Session:
|
| 29 |
+
""" Returns a session specified by year, round and session type """
|
|
|
|
|
|
|
| 30 |
|
| 31 |
# Check if session type is valid
|
| 32 |
if isinstance(session_type, str):
|
|
|
|
| 35 |
|
| 36 |
return fastf1.get_session(year, round, session_type)
|
| 37 |
|
| 38 |
+
def get_season_calendar(year: int) -> str:
|
| 39 |
+
""" Returns the season calendar for the given year """
|
| 40 |
+
season_calendar = fastf1.get_event_schedule(year)
|
| 41 |
+
return parser_utils.parse_season_calendar(season_calendar)
|
| 42 |
+
|
| 43 |
def get_event_info(year: int, round: gp, format: str) -> str:
|
| 44 |
""" Returns the event info for the specified session """
|
| 45 |
|
|
|
|
| 55 |
def get_constructor_standings(year: int) -> str:
|
| 56 |
pass
|
| 57 |
|
| 58 |
+
def get_driver_standings(year: int) -> str:
|
| 59 |
pass
|
| 60 |
|
| 61 |
+
def driver_championship_standings(year: int, driver_name: str) -> str:
|
| 62 |
+
|
| 63 |
+
with open("assets/driver_abbreviations.json") as f:
|
| 64 |
+
driver_abbreviations = json.load(f)
|
| 65 |
+
driver_abbreviation = driver_abbreviations[driver_name]
|
| 66 |
+
ergast = fastf1.ergast.Ergast()
|
| 67 |
+
driver_standings = ergast.get_driver_standings(year).content[0]
|
| 68 |
+
driver_standing = driver_standings[["position", "points", "wins", "driverCode"]].reset_index(drop=True)
|
| 69 |
+
driver_standing = driver_standing[driver_standing["driverCode"] == driver_abbreviation]
|
| 70 |
+
suffix = "st" if driver_standing['position'].iloc[0] == 1 else "nd" if driver_standing['position'].iloc[0] == 2 else "rd" if driver_standing['position'].iloc[0] == 3 else "th"
|
| 71 |
+
standings_string = f"{driver_name} is {driver_standing['position'].iloc[0]}{suffix} with {driver_standing['points'].iloc[0]} points and {driver_standing['wins'].iloc[0]} wins"
|
| 72 |
+
return standings_string
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def constructor_championship_standings(year: int, constructor_name: str) -> str:
|
| 76 |
+
pass
|
| 77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
|
|
|
|
|
|
| 79 |
|
| 80 |
def track_visualization(year: int, round: gp, visualization_type: str, driver_name: str) -> Image:
|
| 81 |
|