f1-telemetry/telemetry/report_common.py
2026-06-13 18:53:52 +03:00

124 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import tempfile
from .parser import Lap, laptime_s, sector_times
def header_block(lap: Lap) -> str:
s = lap.session
t = lap.track
lt = laptime_s(lap)
s1, s2, s3 = sector_times(lap)
lap_n = t.get('Lap', '?')
laps_total = t.get('LapsInRace', '?')
fuel_start = t.get('Fuel at Start', '?')
try:
fuel_start = f'{float(fuel_start):.2f} kg'
except (ValueError, TypeError):
pass
lines = [
f'**Track:** {s.get("track", "?")} ',
f'**Car:** {s.get("car", "?")} ',
f'**Event:** {s.get("event", "?")} ',
f'**Laptime:** {lt:.3f} s (S1 {s1:.3f} / S2 {s2:.3f} / S3 {s3:.3f}) ',
f'**Tyre:** {t.get("Tyre", "?")} ',
f'**Weather:** {t.get("Weather", "?")} ',
f'**Track temp:** {t.get("TrackTemp", "?")} °C **Air:** {t.get("AmbientTemp", "?")} °C ',
f'**Lap:** {lap_n} / {laps_total} ',
f'**Fuel at start:** {fuel_start} ',
]
return '\n'.join(lines)
def setup_summary(lap: Lap) -> str:
s = lap.setup
return (
f'FWing {s.get("FWing","?")} / RWing {s.get("RWing","?")} | '
f'BrakeBias {s.get("BrakeBias","?")}% | '
f'FL {s.get("FLTyrePressure","?")} FR {s.get("FRTyrePressure","?")} '
f'RL {s.get("RLTyrePressure","?")} RR {s.get("RRTyrePressure","?")} PSI'
)
LEGEND_DIST = '- `dist` = LapDistance [m]'
LEGEND_TIME = '- `time` = elapsed LapTime [s]'
LEGEND_SPD = '- `spd` = Speed [km/h]'
LEGEND_THR_BRK = '- `thr` / `brk` = ThrottlePercentage / BrakePercentage [0–100 %]'
LEGEND_STEER = '- `steer` = steering lock [%], negative = left, positive = right'
LEGEND_GEAR = '- `gear` = selected gear (2–8)'
LEGEND_DRS = '- `drs` = DRS active (0 = off, 1 = on)'
LEGEND_GLAT = '- `gLat` = lateral G-force [G], positive = right corner'
LEGEND_GLON = '- `gLon` = longitudinal G-force [G], negative = braking, positive = acceleration'
LEGEND_FUEL = '- `fuel` = FuelRemaining [kg]'
LEGEND_ERS = '- `ers` = ERSSpent [MJ], cumulative energy deployed from ERS'
LEGEND_LOCK = '- LOCK flag = front relative slip (slip km/h / speed km/h × 100) < −10 % while braking (severe lockup only)'
LEGEND_SPIN = '- SPIN flag = rear relative slip > +8 % while on throttle (severe wheelspin only)'
LEGEND_TF = '- `Tf` / `Tr` = surface tyre temperature front/rear average [°C]'
LEGEND_RPM = '- `rpm` = engine revs (rounded to nearest 100)'
LEGEND_SLIP = '- `slipF` / `slipR` = relative wheel slip front/rear [%], negative front = locking tendency, positive rear = wheelspin tendency'
LEGEND_YAW = '- `yaw` = yaw rate [rad/s] (LocalAngularVelocityY); large steer + small yaw = understeer'
LEGEND_SUSP = '- Suspension positions in mm; rake = front avg − rear avg; roll = left avg − right avg per corner (positive = left side compressed)'
LEGEND_DT_SEG = '- `Δt seg` = per-segment time delta (positive = lap X slower in that zone)'
LEGEND_DT_CUM = '- `Δt cum` = cumulative delta at zone end vs lap A [s], negative = lap X faster up to that point'
LEGEND_STEER_G_CAVEAT = '- steer/g and slip balance are speed-dependent — only compare corners of similar Vmin'
def legend(entries: list[str]) -> str:
return '## Legend\n' + '\n'.join(entries)
def md_table(headers: list[str], rows: list[list[str]]) -> str:
sep = ['---'] * len(headers)
lines = [
'| ' + ' | '.join(headers) + ' |',
'| ' + ' | '.join(sep) + ' |',
]
for row in rows:
lines.append('| ' + ' | '.join(str(c) for c in row) + ' |')
return '\n'.join(lines)
def token_estimate(text: str) -> int:
return int(len(text) / 3.5)
def write_report(path: str, text: str) -> tuple[str, int]:
os.makedirs(os.path.dirname(path), exist_ok=True)
dir_ = os.path.dirname(path)
fd, tmp = tempfile.mkstemp(dir=dir_, suffix='.tmp')
try:
# close the raw fd so we can open in text mode (platform newlines, UTF-8)
os.close(fd)
with open(tmp, 'w', encoding='utf-8') as f:
f.write(text)
os.replace(tmp, path)
except Exception:
try:
os.unlink(tmp)
except OSError:
pass
raise
tokens = token_estimate(text)
return os.path.abspath(path), tokens
def load_prompt(mode: str, lang: str) -> str:
here = os.path.dirname(__file__)
p = os.path.normpath(os.path.join(here, '..', 'prompts', lang, f'{mode}.md'))
try:
with open(p, encoding='utf-8') as f:
return f.read().strip()
except FileNotFoundError:
return ''
def report_path(input_path: str, mode: str, other_stem: str = '') -> str:
d = os.path.dirname(os.path.abspath(input_path))
reports_dir = os.path.join(d, 'reports')
stem = os.path.splitext(os.path.basename(input_path))[0]
if mode == 'compare' and other_stem:
fname = f'compare_{stem}_vs_{other_stem}.md'
else:
fname = f'{stem}_{mode}.md'
return os.path.join(reports_dir, fname)