|
import datetime |
|
import os |
|
|
|
import fastf1 |
|
import pandas as pd |
|
from fastapi import FastAPI |
|
from fastapi.middleware.cors import CORSMiddleware |
|
from fastapi.responses import FileResponse, HTMLResponse |
|
from pydantic import BaseModel |
|
|
|
import available_data |
|
|
|
app = FastAPI() |
|
|
|
origins = [ |
|
"http://localhost", |
|
"http://localhost:8080", |
|
"http://localhost:3000", |
|
] |
|
|
|
app.add_middleware( |
|
CORSMiddleware, |
|
allow_origins=origins, |
|
allow_credentials=True, |
|
allow_methods=["*"], |
|
allow_headers=["*"], |
|
) |
|
|
|
|
|
@app.get("/", response_model=None) |
|
async def root(): |
|
return HTMLResponse( |
|
content="""<iframe src="https://tracinginsights-f1-analysis.hf.space" frameborder="0" style="width:100%; height:100%;" scrolling="yes" allowfullscreen:"yes"></iframe>""", |
|
status_code=200) |
|
|
|
|
|
|
|
@app.get("/years", response_model=None) |
|
def years_available() -> any: |
|
|
|
current_year = datetime.datetime.now().year |
|
years = list(range(2018, current_year+1)) |
|
|
|
years.reverse() |
|
years = [{"label": str(year), "value": year} for year in years] |
|
return {"years": years} |
|
|
|
|
|
|
|
|
|
|
|
@app.get("/{year}", response_model=None) |
|
def events_available(year: int) -> any: |
|
|
|
data = available_data.LatestData(year) |
|
events = data.get_events() |
|
events = [{"label": event, "value": i} for i, event in enumerate(events)] |
|
events.reverse() |
|
|
|
return {"events": events} |
|
|
|
|
|
|
|
|
|
@app.get("/{year}/{event}", response_model=None) |
|
def sessions_available(year: int, event: str) -> any: |
|
|
|
data = available_data.LatestData(year) |
|
sessions = data.get_sessions(event) |
|
sessions = [{"label": session, "value": session} for session in sessions] |
|
|
|
return {"sessions": sessions} |
|
|
|
|
|
|
|
|
|
@app.get("/{year}/{event}/{session}", response_model=None) |
|
def session_drivers(year: int, event: str, session: str) -> any: |
|
|
|
f1session = fastf1.get_session(year, event, session) |
|
f1session.load(telemetry=False, weather=False, messages=False) |
|
laps = f1session.laps |
|
team_colors = available_data.team_colors(year) |
|
|
|
|
|
drivers = laps.Driver.unique() |
|
|
|
drivers = [{"color": team_colors[laps[laps.Driver == |
|
driver].Team.iloc[0]], "label": driver, "value": driver} for driver in drivers] |
|
|
|
return {"drivers": drivers} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/{year}/{event}/{session}/{driver}", response_model=None) |
|
def laps_data(year: int, event: str, session: str, driver: str) -> any: |
|
|
|
|
|
f1session = fastf1.get_session(year, event, session) |
|
f1session.load(telemetry=False, weather=False, messages=False) |
|
laps = f1session.laps |
|
team_colors = available_data.team_colors(year) |
|
|
|
|
|
drivers = laps.Driver.unique() |
|
|
|
drivers = [{"color": team_colors[laps[laps.Driver == |
|
driver].Team.iloc[0]], "label": driver, "value": driver} for driver in drivers] |
|
|
|
driver_laps = laps.pick_driver(driver) |
|
driver_laps['LapTime'] = driver_laps['LapTime'].dt.total_seconds() |
|
compound_colors = { |
|
"SOFT": "#FF0000", |
|
"MEDIUM": "#FFFF00", |
|
"HARD": "#FFFFFF", |
|
"INTERMEDIATE": "#00FF00", |
|
"WET": "#088cd0", |
|
|
|
} |
|
|
|
driver_laps_data = [] |
|
|
|
for _, row in driver_laps.iterrows(): |
|
|
|
if row['LapTime'] > 0: |
|
lap = {f"{driver}": row['LapTime'], |
|
f"{driver}_compound": row['Compound'], |
|
f"{driver}_compound_color": compound_colors[row['Compound']], |
|
"lapnumber": row['LapNumber']} |
|
else: |
|
lap = {"lapnumber": row['LapNumber']} |
|
|
|
driver_laps_data.append(lap) |
|
|
|
return {"chartData": driver_laps_data} |
|
|
|
|
|
@app.get("/{year}/{event}/{session}/{driver}/{lap_number}", response_model=None) |
|
def telemetry_data(year: int, event: str, session: str, driver: str, lap_number: int) -> any: |
|
|
|
f1session = fastf1.get_session(year, event, session) |
|
f1session.load(telemetry=True, weather=False, messages=False) |
|
laps = f1session.laps |
|
|
|
driver_laps = laps.pick_driver(driver) |
|
driver_laps['LapTime'] = driver_laps['LapTime'].dt.total_seconds() |
|
|
|
|
|
selected_lap = driver_laps[driver_laps.LapNumber == lap_number] |
|
|
|
telemetry = selected_lap.get_telemetry() |
|
telemetry['Time'] = telemetry['Time'].dt.total_seconds() |
|
|
|
laptime = selected_lap.LapTime.values[0] |
|
data_key = f"{driver} - Lap {int(lap_number)} - {year} {session} [{int(laptime//60)}:{laptime%60}]" |
|
|
|
brake_tel = [] |
|
drs_tel = [] |
|
gear_tel = [] |
|
rpm_tel = [] |
|
speed_tel = [] |
|
throttle_tel = [] |
|
time_tel = [] |
|
track_map = [] |
|
|
|
for _, row in telemetry.iterrows(): |
|
|
|
brake = {"x": row['Distance'], |
|
"y": row['Brake'], |
|
} |
|
brake_tel.append(brake) |
|
|
|
drs = {"x": row['Distance'], |
|
"y": row['DRS'], |
|
} |
|
drs_tel.append(drs) |
|
|
|
gear = {"x": row['Distance'], |
|
"y": row['nGear'], |
|
} |
|
gear_tel.append(gear) |
|
|
|
rpm = {"x": row['Distance'], |
|
"y": row['RPM'], |
|
} |
|
rpm_tel.append(rpm) |
|
|
|
speed = {"x": row['Distance'], |
|
"y": row['Speed'], |
|
} |
|
speed_tel.append(speed) |
|
|
|
throttle = {"x": row['Distance'], |
|
"y": row['Throttle'], |
|
} |
|
throttle_tel.append(throttle) |
|
|
|
time = {"x": row['Distance'], |
|
"y": row['Time'], |
|
} |
|
time_tel.append(time) |
|
|
|
track = {"x": row['X'], |
|
"y": row['Y'], |
|
} |
|
track_map.append(track) |
|
|
|
telemetry_data = { |
|
"telemetryData":{ |
|
"brake": brake_tel, |
|
"dataKey": data_key, |
|
"drs": drs_tel, |
|
"gear": gear_tel, |
|
"rpm": rpm_tel, |
|
"speed": speed_tel, |
|
"throttle": throttle_tel, |
|
"time": time_tel, |
|
"trackMap": track_map, |
|
} |
|
} |
|
|
|
return telemetry_data |
|
|