document profile mode, new flags, and tunable constants

This commit is contained in:
Andrew Pimenov 2026-06-18 03:47:42 +03:00
parent 0661ff4322
commit 22ca7cc24f
4 changed files with 64 additions and 8 deletions

View file

@ -17,7 +17,8 @@ telemetry/
report_technique.py Driving report (corners, straights, cost, trace). report_technique.py Driving report (corners, straights, cost, trace).
report_setup.py Car report (setup, balance, tyres, brakes, suspension, phases). report_setup.py Car report (setup, balance, tyres, brakes, suspension, phases).
report_compare.py Two+ laps side by side, per-corner and cumulative delta. report_compare.py Two+ laps side by side, per-corner and cumulative delta.
report_race.py A folder of laps: lap times (with position), stints, wear, thermals, ERS. report_race.py A folder of laps: lap times (with position), stints, wear, thermals, ERS. Dedups duplicate lap numbers.
report_profile.py A folder of laps: cheap cross-lap corner tendencies (median per corner, per dominant compound) + auto-picked deep-dive laps. No trace.
rename.py Insert session type + lap number (P1_L7) into filenames; with races_dir, sort into races/<track>/<session>/ and recurse subdirectories. rename.py Insert session type + lap number (P1_L7) into filenames; with races_dir, sort into races/<track>/<session>/ and recurse subdirectories.
gui.py tkinter window; per-mode browse memory; runs generation/rename on a worker thread. gui.py tkinter window; per-mode browse memory; runs generation/rename on a worker thread.
prompts/ LLM analysis prompts, ru/ and en/ subdirectories, one file per mode. Auto-appended to every report. prompts/ LLM analysis prompts, ru/ and en/ subdirectories, one file per mode. Auto-appended to every report.
@ -30,7 +31,7 @@ tests/ pytest suite + fixture laps.
2. **`parser.load_lap`** reads the file as UTF-8 and splits it into four meta blocks (session, track, setup) plus the 108-channel telemetry table. Channel names are normalised by stripping the ` [unit]` suffix. Every column that is entirely zero is dropped — the game writes many dead channels (see Gotchas). 2. **`parser.load_lap`** reads the file as UTF-8 and splits it into four meta blocks (session, track, setup) plus the 108-channel telemetry table. Channel names are normalised by stripping the ` [unit]` suffix. Every column that is entirely zero is dropped — the game writes many dead channels (see Gotchas).
3. **`segments.detect_corners`** walks the samples, marks each as "cornering" when `|Steer| > STEER_ON` or `Brake > BRAKE_ON`, merges adjacent zones closer than `MERGE_GAP_M`, drops zones shorter than `MIN_LEN_M`, and numbers what's left T1..Tn by distance. For each zone it calls **`corner_metrics.corner_from_zone`**, which extracts the braking point, apex, gear, full-throttle point, peak brake/gLat, relative lock%/spin%, coast distance, and rear tyre temperature peak. `straights` fills the gaps between corners. 3. **`segments.detect_corners`** walks the samples, marks each as "cornering" when `|Steer| > STEER_ON` or `Brake > BRAKE_ON`, merges adjacent zones closer than `MERGE_GAP_M`, drops zones shorter than `MIN_LEN_M`, and numbers what's left T1..Tn by distance. For each zone it calls **`corner_metrics.corner_from_zone`**, which extracts the braking point, apex, gear, full-throttle point, peak brake/gLat, relative lock%/spin%, coast distance, and rear tyre temperature peak. `straights` fills the gaps between corners.
4. **`resample.adaptive_points`** builds a distance grid that is dense inside (and on approach to) corners and sparse on straights — the step sizes default to the lap's own median sample spacing via `auto_steps`, so denser raw telemetry yields a denser trace. **`sample_at`** interpolates each channel onto that grid (nearest-sample for discrete channels like Gear/DRS). 4. **`resample.adaptive_points`** builds a distance grid that is dense inside (and on approach to) corners and sparse on straights — the step sizes default to the lap's own median sample spacing via `auto_steps`, so denser raw telemetry yields a denser trace. **`sample_at`** interpolates each channel onto that grid (nearest-sample for discrete channels like Gear/DRS).
5. The **`report_<mode>.generate(…, lang)`** function assembles Markdown from `report_common` helpers (`header_block`, `md_table`, `legend`) and the data above. It then calls **`load_prompt(mode, lang)`** to read the matching prompt from `prompts/<lang>/<mode>.md` and appends it after a `---` separator. Finally **`write_report`** writes atomically (temp file + `os.replace`) and returns `(abs_path, tokens)`. 5. The **`report_<mode>.generate(…, lang, include_prompt=True)`** function assembles Markdown from `report_common` helpers (`header_block`, `md_table`, `legend`) and the data above. When `include_prompt` is set it calls **`load_prompt(mode, lang)`** to read the matching prompt from `prompts/<lang>/<mode>.md` and appends it after a `---` separator (CLI `--no-prompt` / GUI checkbox turn this off). Finally **`write_report`** writes atomically (temp file + `os.replace`) and returns `(abs_path, tokens)`. Before generating, `__main__` skips the run via **`is_fresh(report, sources)`** when an up-to-date report exists (override with `--force`).
6. **`__main__`** prints that path and `~N tokens (budget 60k)`. The **GUI** shows the same tuple in its log instead of printing. 6. **`__main__`** prints that path and `~N tokens (budget 60k)`. The **GUI** shows the same tuple in its log instead of printing.
## Adding things ## Adding things
@ -41,6 +42,23 @@ tests/ pytest suite + fixture laps.
**A new corner metric.** Add a field to the `Corner` dataclass in `segments.py` and compute it in `corner_metrics.corner_from_zone`. Because `Corner` is frozen, set it through the constructor. **A new corner metric.** Add a field to the `Corner` dataclass in `segments.py` and compute it in `corner_metrics.corner_from_zone`. Because `Corner` is frozen, set it through the constructor.
## Assumptions & tunables
Two kinds of constants. **Detection** thresholds are in telemetry units and uniform across F1 22 — they decide *where* a boundary is, not the conclusion, so they are not track-tuned. **Interpretation** constants encode racing judgment that genuinely varies; reports always print the raw number next to any flag/verdict, so a debatable threshold never hides the data.
| Constant | File | Kind | Basis / sensitivity |
|----------|------|------|---------------------|
| `STEER_ON 6`, `BRAKE_ON 5`, `BRAKE_MARK 20`, `FULL_THROTTLE 98` | `segments` / `corner_metrics` | detection | percent of input range, game-uniform |
| `MERGE_GAP_M 40` + `merge_gap_for` (clamp 28–60) | `segments` | detection | **adaptive**: scales with `Tracklen` around the Zandvoort anchor so chicanes/long circuits self-tune |
| `MIN_LEN_M 15`, `_SAFE_SPEED_FLOOR 30`, `0.3 s` throttle window | `segments` / `corner_metrics` | detection | geometry / divide guard / debounce |
| `resample` dense=median, sparse=8×median | `resample` | detection | self-tunes to sample rate |
| `LOCKUP −10 %`, `SPIN +8 %` | `segments` | interpretation | severe-only flags; raw `lock%`/`spin%` always shown |
| `FUEL 0.03–0.05 s/kg` | `report_compare` | interpretation | track-varying; emitted as a **range** with the rate printed |
| `diff ±0.5` US/OS | `report_setup` | interpretation | relative to the lap's slip baseline; raw front/rear slip shown |
| profile `*_REL` multipliers + `*_FLOOR` / `TR` margins | `report_profile` | interpretation | multipliers are **relative to the session median**; floors are noise gates; medians shown in the table |
If a future track needs a different corner grouping, `merge_gap_for` already adapts by length; only a genuinely unusual layout would want a manual nudge there.
## Gotchas ## Gotchas
**Files are UTF-8, the OS default here is cp1251.** `parser.load_lap` always passes `encoding='utf-8'`; opening a telemetry file with the default codec raises `UnicodeDecodeError` on the first non-ASCII byte. `rename.read_lap_number` reads only the first five lines but must use the same encoding. **Files are UTF-8, the OS default here is cp1251.** `parser.load_lap` always passes `encoding='utf-8'`; opening a telemetry file with the default codec raises `UnicodeDecodeError` on the first non-ASCII byte. `rename.read_lap_number` reads only the first five lines but must use the same encoding.

View file

@ -17,7 +17,8 @@ telemetry/
report_technique.py Отчёт о пилотировании (повороты, прямые, расход, трасса). report_technique.py Отчёт о пилотировании (повороты, прямые, расход, трасса).
report_setup.py Отчёт о машине (сетап, баланс, шины, тормоза, подвеска, фазы). report_setup.py Отчёт о машине (сетап, баланс, шины, тормоза, подвеска, фазы).
report_compare.py Два+ круга рядом, дельта по поворотам и накопленная. report_compare.py Два+ круга рядом, дельта по поворотам и накопленная.
report_race.py Папка кругов: лаптаймы (с позицией), стинты, износ, тепло, ERS. report_race.py Папка кругов: лаптаймы (с позицией), стинты, износ, тепло, ERS. Дедуп дублей номеров кругов.
report_profile.py Папка кругов: дешёвые тенденции по поворотам (медиана на поворот, по доминирующему составу) + авто-выбор кругов для разбора. Без трассы.
rename.py Вставка типа сессии + номера круга (P1_L7) в имя; с races_dir — сортировка в races/<track>/<session>/ и рекурсия по подпапкам. rename.py Вставка типа сессии + номера круга (P1_L7) в имя; с races_dir — сортировка в races/<track>/<session>/ и рекурсия по подпапкам.
gui.py Окно tkinter; память последней папки по режиму; генерация/переименование в потоке. gui.py Окно tkinter; память последней папки по режиму; генерация/переименование в потоке.
prompts/ Промпты LLM, подпапки ru/ и en/, по одному файлу на режим. Добавляются в конец каждого отчёта. prompts/ Промпты LLM, подпапки ru/ и en/, по одному файлу на режим. Добавляются в конец каждого отчёта.
@ -30,7 +31,7 @@ tests/ Набор pytest + фикстуры-круги.
2. **`parser.load_lap`** читает файл как UTF-8 и делит на четыре мета-блока (session, track, setup) плюс таблицу телеметрии на 108 каналов. Имена каналов нормализуются срезанием суффикса ` [unit]`. Каждая колонка, целиком состоящая из нулей, отбрасывается — игра пишет много мёртвых каналов (см. «Подводные камни»). 2. **`parser.load_lap`** читает файл как UTF-8 и делит на четыре мета-блока (session, track, setup) плюс таблицу телеметрии на 108 каналов. Имена каналов нормализуются срезанием суффикса ` [unit]`. Каждая колонка, целиком состоящая из нулей, отбрасывается — игра пишет много мёртвых каналов (см. «Подводные камни»).
3. **`segments.detect_corners`** проходит по сэмплам, помечает сэмпл как «в повороте», если `|Steer| > STEER_ON` или `Brake > BRAKE_ON`, сливает соседние зоны с зазором меньше `MERGE_GAP_M`, отбрасывает зоны короче `MIN_LEN_M` и нумерует оставшиеся T1..Tn по дистанции. Для каждой зоны вызывается **`corner_metrics.corner_from_zone`**, которая извлекает точку торможения, апекс, передачу, точку полного газа, пик тормоза/gLat, относительные lock%/spin%, дистанцию наката и пик температуры задней шины. `straights` заполняет промежутки между поворотами. 3. **`segments.detect_corners`** проходит по сэмплам, помечает сэмпл как «в повороте», если `|Steer| > STEER_ON` или `Brake > BRAKE_ON`, сливает соседние зоны с зазором меньше `MERGE_GAP_M`, отбрасывает зоны короче `MIN_LEN_M` и нумерует оставшиеся T1..Tn по дистанции. Для каждой зоны вызывается **`corner_metrics.corner_from_zone`**, которая извлекает точку торможения, апекс, передачу, точку полного газа, пик тормоза/gLat, относительные lock%/spin%, дистанцию наката и пик температуры задней шины. `straights` заполняет промежутки между поворотами.
4. **`resample.adaptive_points`** строит сетку по дистанции — плотную внутри поворотов (и на подходе) и редкую на прямых; шаги по умолчанию берутся из медианного интервала сэмплов круга через `auto_steps`, так что более плотная сырая телеметрия даёт более плотную трассу. **`sample_at`** интерполирует каждый канал на эту сетку (ближайший сэмпл для дискретных вроде Gear/DRS). 4. **`resample.adaptive_points`** строит сетку по дистанции — плотную внутри поворотов (и на подходе) и редкую на прямых; шаги по умолчанию берутся из медианного интервала сэмплов круга через `auto_steps`, так что более плотная сырая телеметрия даёт более плотную трассу. **`sample_at`** интерполирует каждый канал на эту сетку (ближайший сэмпл для дискретных вроде Gear/DRS).
5. Функция **`report_<режим>.generate(…, lang)`** собирает Markdown из помощников `report_common` (`header_block`, `md_table`, `legend`) и данных выше. Затем вызывает **`load_prompt(mode, lang)`**, которая читает промпт из `prompts/<lang>/<mode>.md` и добавляет его после разделителя `---`. Финальный текст пишется через **`write_report`** атомарно (временный файл + `os.replace`), возвращается `(abs_path, tokens)`. 5. Функция **`report_<режим>.generate(…, lang, include_prompt=True)`** собирает Markdown из помощников `report_common` (`header_block`, `md_table`, `legend`) и данных выше. При `include_prompt` вызывает **`load_prompt(mode, lang)`**, которая читает промпт из `prompts/<lang>/<mode>.md` и добавляет его после разделителя `---` (CLI `--no-prompt` / чекбокс GUI это отключают). Финальный текст пишется через **`write_report`** атомарно (временный файл + `os.replace`), возвращается `(abs_path, tokens)`. Перед генерацией `__main__` пропускает прогон через **`is_fresh(report, sources)`**, если свежий отчёт уже есть (override — `--force`).
6. **`__main__`** печатает путь и `~N tokens (budget 60k)`. **GUI** показывает тот же кортеж в логе вместо печати. 6. **`__main__`** печатает путь и `~N tokens (budget 60k)`. **GUI** показывает тот же кортеж в логе вместо печати.
## Как добавлять ## Как добавлять
@ -41,6 +42,23 @@ tests/ Набор pytest + фикстуры-круги.
**Новая метрика поворота.** Добавь поле в dataclass `Corner` в `segments.py` и посчитай его в `corner_metrics.corner_from_zone`. Поскольку `Corner` — frozen, задавай через конструктор. **Новая метрика поворота.** Добавь поле в dataclass `Corner` в `segments.py` и посчитай его в `corner_metrics.corner_from_zone`. Поскольку `Corner` — frozen, задавай через конструктор.
## Допущения и тюнящиеся константы
Два рода констант. **Детекция** — пороги в единицах телеметрии, одинаковы во всей F1 22: решают, *где* граница, а не вывод, поэтому не тюнингуются под трассу. **Интерпретация** — доменное суждение, которое реально варьируется; в отчётах рядом с любым флагом/вердиктом всегда печатается сырое число, так что спорный порог не прячет данные.
| Константа | Файл | Род | Основа / чувствительность |
|-----------|------|-----|---------------------------|
| `STEER_ON 6`, `BRAKE_ON 5`, `BRAKE_MARK 20`, `FULL_THROTTLE 98` | `segments` / `corner_metrics` | детекция | % от диапазона ввода, одинаково в игре |
| `MERGE_GAP_M 40` + `merge_gap_for` (clamp 28–60) | `segments` | детекция | **адаптивно**: масштабируется по `Tracklen` вокруг якоря Zandvoort — шиканы/длинные трассы самотюнятся |
| `MIN_LEN_M 15`, `_SAFE_SPEED_FLOOR 30`, окно газа `0.3 с` | `segments` / `corner_metrics` | детекция | геометрия / защита деления / дебаунс |
| `resample` dense=median, sparse=8×median | `resample` | детекция | самонастройка под частоту данных |
| `LOCKUP −10 %`, `SPIN +8 %` | `segments` | интерпретация | флаги severe-only; сырые `lock%`/`spin%` всегда показаны |
| `FUEL 0.03–0.05 с/кг` | `report_compare` | интерпретация | зависит от трассы; выдаётся **диапазоном** с печатью ставки |
| `diff ±0.5` US/OS | `report_setup` | интерпретация | относительно baseline скольжения круга; сырое front/rear показано |
| profile `*_REL` множители + `*_FLOOR` / `TR` поля | `report_profile` | интерпретация | множители **относительно медианы сессии**; полы — шумовые гейты; медианы в таблице |
Если будущая трасса потребует другой группировки поворотов — `merge_gap_for` уже адаптируется по длине; ручная правка нужна лишь на совсем нестандартной конфигурации.
## Подводные камни ## Подводные камни
**Файлы в UTF-8, а кодировка ОС здесь — cp1251.** `parser.load_lap` всегда передаёт `encoding='utf-8'`; открытие файла телеметрии дефолтным кодеком падает с `UnicodeDecodeError` на первом не-ASCII байте. `rename.read_lap_number` читает только первые пять строк, но обязан использовать ту же кодировку. **Файлы в UTF-8, а кодировка ОС здесь — cp1251.** `parser.load_lap` всегда передаёт `encoding='utf-8'`; открытие файла телеметрии дефолтным кодеком падает с `UnicodeDecodeError` на первом не-ASCII байте. `rename.read_lap_number` читает только первые пять строк, но обязан использовать ту же кодировку.

View file

@ -21,18 +21,23 @@ Download or clone the repository. Keep your telemetry CSVs in the parent folder
## What it does ## What it does
Five modes. Four produce reports, one renames files. Six modes. Five produce reports, one renames files.
| Mode | Input | Use it to analyse | | Mode | Input | Use it to analyse |
|------|-------|-------------------| |------|-------|-------------------|
| `technique` | one lap | **how** you drive — braking points, apex speeds, throttle application, lockups, resource cost | | `technique` | one lap | **how** you drive — braking points, apex speeds, throttle application, lockups, resource cost |
| `setup` | one lap | **what** is set — balance (US/OS), tyre temps, brakes, suspension rake & roll | | `setup` | one lap | **what** is set — balance (US/OS), tyre temps, brakes, suspension rake & roll |
| `compare` | two+ laps | **where** one lap is faster — per-corner and cumulative delta | | `compare` | two+ laps | **where** one lap is faster — per-corner and cumulative delta, plus a deterministic `Verdict` (fuel-corrected) |
| `race` | a folder of laps | the whole race — pace, stint degradation, tyre wear, ERS per lap | | `race` | a folder of laps | the whole race — pace, stint degradation, tyre wear, ERS per lap |
| `profile` | a folder of laps | **cheap** (~400 tokens) cross-lap driver tendencies per tyre compound (median coast/lock/spin per corner, flagged relative to the session) + auto-picked laps to deep-dive. Track-agnostic: corners are clustered by apex distance, not index |
| `rename` | files/folder | insert session type and lap number into each filename (`..._74.074_...` → `..._P1_L7_74.074_...`) | | `rename` | files/folder | insert session type and lap number into each filename (`..._74.074_...` → `..._P1_L7_74.074_...`) |
Reports include a legend explaining every column and have the analysis prompt auto-appended at the end — just drop the file into an LLM. Prompts come in RU and EN; pick with `--lang en` on the CLI or the language radio in the GUI. Reports include a legend explaining every column and have the analysis prompt auto-appended at the end — just drop the file into an LLM. Prompts come in RU and EN; pick with `--lang en` on the CLI or the language radio in the GUI.
**Flags:** `--no-prompt` omits the embedded analysis prompt (smaller files for agent pipelines; in the GUI it's the **Include prompt** checkbox). `--force` regenerates even when an up-to-date report already exists (runs are otherwise skipped as `cached`).
> Typical optimized flow: run `profile` first to see chronic tendencies and which laps matter, then generate `technique`/`setup`/`compare` only for those laps with `--no-prompt`.
### Folder layout ### Folder layout
``` ```
@ -66,10 +71,15 @@ python -m telemetry technique races/Zandvoort/Practice/lap.csv
python -m telemetry setup races/Zandvoort/Practice/lap.csv python -m telemetry setup races/Zandvoort/Practice/lap.csv
python -m telemetry compare races/Zandvoort/Practice/lap_a.csv races/Zandvoort/Practice/lap_b.csv python -m telemetry compare races/Zandvoort/Practice/lap_a.csv races/Zandvoort/Practice/lap_b.csv
python -m telemetry race races/Zandvoort/Race python -m telemetry race races/Zandvoort/Race
python -m telemetry profile races/Zandvoort/Race # cheap cross-lap tendencies + lap picks
python -m telemetry rename races/Zandvoort/Practice # or individual files python -m telemetry rename races/Zandvoort/Practice # or individual files
# choose prompt language (default: ru) # choose prompt language (default: ru)
python -m telemetry technique races/Zandvoort/Practice/lap.csv --lang en python -m telemetry technique races/Zandvoort/Practice/lap.csv --lang en
# agent pipeline: drop the prompt, reuse fresh reports
python -m telemetry technique races/Zandvoort/Practice/lap.csv --no-prompt
python -m telemetry technique races/Zandvoort/Practice/lap.csv --force # ignore cache
``` ```
Every report run prints the output path and a token estimate: Every report run prints the output path and a token estimate:

View file

@ -21,18 +21,23 @@ python -m telemetry technique "races/Zandvoort/Практика/zandvoort_P1_L7_
## Что умеет ## Что умеет
Пять режимов. Четыре строят отчёты, один переименовывает файлы. Шесть режимов. Пять строят отчёты, один переименовывает файлы.
| Режим | Вход | Для анализа | | Режим | Вход | Для анализа |
|-------|------|-------------| |-------|------|-------------|
| `technique` | один круг | **как** едешь — точки торможения, скорости в апексах, работа газом, блокировки, расход ресурсов | | `technique` | один круг | **как** едешь — точки торможения, скорости в апексах, работа газом, блокировки, расход ресурсов |
| `setup` | один круг | **что** настроено — баланс (US/OS), температуры шин, тормоза, rake и крен подвески | | `setup` | один круг | **что** настроено — баланс (US/OS), температуры шин, тормоза, rake и крен подвески |
| `compare` | два+ круга | **где** один круг быстрее — дельта по поворотам и накопленная | | `compare` | два+ круга | **где** один круг быстрее — дельта по поворотам и накопленная, плюс детерминированный `Verdict` (с топливной поправкой) |
| `race` | папка кругов | вся гонка — темп, деградация в стинтах, износ резины, ERS по кругам | | `race` | папка кругов | вся гонка — темп, деградация в стинтах, износ резины, ERS по кругам |
| `profile` | папка кругов | **дёшево** (~400 токенов) тенденции пилота по каждому составу (медиана coast/lock/spin на поворот, флаги относительно сессии) + авто-выбор кругов. Универсально: повороты кластеризуются по дистанции апекса, не по индексу |
| `rename` | файлы/папка | вставить тип сессии и номер круга в имя файла (`..._74.074_...` → `..._P1_L7_74.074_...`) | | `rename` | файлы/папка | вставить тип сессии и номер круга в имя файла (`..._74.074_...` → `..._P1_L7_74.074_...`) |
Отчёты содержат легенду с пояснением каждой колонки, а промпт анализа добавляется в конец файла автоматически — достаточно скинуть файл в LLM. Промпты доступны на RU и EN; выбирается флагом `--lang en` в CLI или переключателем языка в GUI. Отчёты содержат легенду с пояснением каждой колонки, а промпт анализа добавляется в конец файла автоматически — достаточно скинуть файл в LLM. Промпты доступны на RU и EN; выбирается флагом `--lang en` в CLI или переключателем языка в GUI.
**Флаги:** `--no-prompt` убирает встроенный промпт (меньше файлы для агентных конвейеров; в GUI — чекбокс **Включить промпт**). `--force` перегенерирует, даже если свежий отчёт уже есть (иначе прогон пропускается как `cached`).
> Оптимальный порядок: сначала `profile` — увидеть хронические тенденции и какие круги важны, затем `technique`/`setup`/`compare` только по этим кругам с `--no-prompt`.
### Структура папок ### Структура папок
``` ```
@ -66,10 +71,15 @@ python -m telemetry technique races/Zandvoort/Практика/lap.csv
python -m telemetry setup races/Zandvoort/Практика/lap.csv python -m telemetry setup races/Zandvoort/Практика/lap.csv
python -m telemetry compare races/Zandvoort/Практика/lap_a.csv races/Zandvoort/Практика/lap_b.csv python -m telemetry compare races/Zandvoort/Практика/lap_a.csv races/Zandvoort/Практика/lap_b.csv
python -m telemetry race races/Zandvoort/Гонка python -m telemetry race races/Zandvoort/Гонка
python -m telemetry profile races/Zandvoort/Гонка # дешёвые тенденции по всем кругам + авто-выбор
python -m telemetry rename races/Zandvoort/Практика # или отдельные файлы python -m telemetry rename races/Zandvoort/Практика # или отдельные файлы
# выбор языка промпта (по умолчанию: ru) # выбор языка промпта (по умолчанию: ru)
python -m telemetry technique races/Zandvoort/Практика/lap.csv --lang en python -m telemetry technique races/Zandvoort/Практика/lap.csv --lang en
# агентный конвейер: убрать промпт, переиспользовать свежие отчёты
python -m telemetry technique races/Zandvoort/Практика/lap.csv --no-prompt
python -m telemetry technique races/Zandvoort/Практика/lap.csv --force # игнорировать кэш
``` ```
Каждый прогон печатает путь к отчёту и оценку токенов: Каждый прогон печатает путь к отчёту и оценку токенов: