diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index c95a73f..6aab26a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -13,14 +13,14 @@ telemetry/ segments.py Lap -> corners & straights. Zone detection + numbering. corner_metrics.py Per-zone number crunching: braking point, lock/spin, coast, temps. resample.py Adaptive distance grid + channel interpolation for the trace. - report_common.py Header block, legend strings, md_table, token_estimate, atomic write. + report_common.py Header block, legend strings, md_table, token_estimate, load_prompt, atomic write. report_technique.py Driving report (corners, straights, cost, trace). 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_race.py A folder of laps: lap times, stints, wear, thermals, ERS. - rename.py Insert lap number into filenames; skip already-processed. - gui.py tkinter window; runs generation/rename on a worker thread. -prompts/ Russian LLM prompts, one per report mode. + report_race.py A folder of laps: lap times (with position), stints, wear, thermals, ERS. + rename.py Insert session type + lap number (e.g. P1_L7) into filenames; skip processed. + 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. tests/ pytest suite + fixture laps. ``` @@ -30,7 +30,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). 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). -5. The **`report_.generate`** function assembles Markdown from `report_common` helpers (`header_block`, `md_table`, `legend`) and the data above, then calls **`report_common.write_report`**, which writes atomically (temp file + `os.replace`) and returns `(abs_path, tokens)`. +5. The **`report_.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//.md` and appends it after a `---` separator. Finally **`write_report`** writes atomically (temp file + `os.replace`) and returns `(abs_path, tokens)`. 6. **`__main__`** prints that path and `~N tokens (budget 60k)`. The **GUI** shows the same tuple in its log instead of printing. ## Adding things @@ -53,6 +53,6 @@ tests/ pytest suite + fixture laps. **The setup row has a trailing comma** (an empty `FuelLoad` tail field in some exports). The parser drops trailing empties so the setup dict has no blank-string key. -**Rename idempotency hinges on the `L` token.** `lap_token_present` is the single source of truth for "already processed". Changing the token format means changing both `insert_lap_token` and `lap_token_present` together, or rename stops being safe to re-run. +**Rename idempotency hinges on TWO tokens.** A file is considered processed only when both a session token (`P1`, `Q2`, `R`, …, matched by `_SESSION_PAT`) and a lap token (`L`) are present in the stem. Both `session_token_present` and `lap_token_present` are the joint source of truth — changing either token format means updating both the insert and the presence-check functions together. -**Reports go next to the input, not next to the program.** `report_path` derives the `reports/` directory from the *input CSV's* folder; `race` mode computes it from the race folder's parent. Moving the tool does not move where reports land. +**Reports go next to the input, not next to the program.** `report_path` derives the `reports/` directory from the *input CSV's* folder. `race` mode puts the report inside the race session folder (`/reports/`). Moving the tool does not move where reports land. diff --git a/ARCHITECTURE.ru.md b/ARCHITECTURE.ru.md index 536a47a..5f0d2b3 100644 --- a/ARCHITECTURE.ru.md +++ b/ARCHITECTURE.ru.md @@ -13,14 +13,14 @@ telemetry/ segments.py Lap -> повороты и прямые. Детекция зон + нумерация. corner_metrics.py Подсчёт по зоне: точка торможения, lock/spin, накат, температуры. resample.py Адаптивная сетка по дистанции + интерполяция каналов для трассы. - report_common.py Шапка, строки легенды, md_table, token_estimate, атомарная запись. + report_common.py Шапка, строки легенды, md_table, token_estimate, load_prompt, атомарная запись. report_technique.py Отчёт о пилотировании (повороты, прямые, расход, трасса). report_setup.py Отчёт о машине (сетап, баланс, шины, тормоза, подвеска, фазы). report_compare.py Два+ круга рядом, дельта по поворотам и накопленная. - report_race.py Папка кругов: лаптаймы, стинты, износ, тепло, ERS. - rename.py Вставка номера круга в имена файлов; пропуск обработанных. - gui.py Окно tkinter; генерация/переименование в рабочем потоке. -prompts/ Русские промпты для LLM, по одному на режим. + report_race.py Папка кругов: лаптаймы (с позицией), стинты, износ, тепло, ERS. + rename.py Вставка типа сессии + номера круга (P1_L7); пропуск обработанных. + gui.py Окно tkinter; память последней папки по режиму; генерация/переименование в потоке. +prompts/ Промпты LLM, подпапки ru/ и en/, по одному файлу на режим. Добавляются в конец каждого отчёта. tests/ Набор pytest + фикстуры-круги. ``` @@ -30,7 +30,7 @@ tests/ Набор pytest + фикстуры-круги. 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` заполняет промежутки между поворотами. 4. **`resample.adaptive_points`** строит сетку по дистанции — плотную внутри поворотов (и на подходе) и редкую на прямых; шаги по умолчанию берутся из медианного интервала сэмплов круга через `auto_steps`, так что более плотная сырая телеметрия даёт более плотную трассу. **`sample_at`** интерполирует каждый канал на эту сетку (ближайший сэмпл для дискретных вроде Gear/DRS). -5. Функция **`report_<режим>.generate`** собирает Markdown из помощников `report_common` (`header_block`, `md_table`, `legend`) и данных выше, затем вызывает **`report_common.write_report`**, которая пишет атомарно (временный файл + `os.replace`) и возвращает `(abs_path, tokens)`. +5. Функция **`report_<режим>.generate(…, lang)`** собирает Markdown из помощников `report_common` (`header_block`, `md_table`, `legend`) и данных выше. Затем вызывает **`load_prompt(mode, lang)`**, которая читает промпт из `prompts//.md` и добавляет его после разделителя `---`. Финальный текст пишется через **`write_report`** атомарно (временный файл + `os.replace`), возвращается `(abs_path, tokens)`. 6. **`__main__`** печатает путь и `~N tokens (budget 60k)`. **GUI** показывает тот же кортеж в логе вместо печати. ## Как добавлять @@ -53,6 +53,6 @@ tests/ Набор pytest + фикстуры-круги. **Строка сетапа заканчивается лишней запятой** (пустой хвост `FuelLoad` в части экспортов). Парсер отбрасывает пустые хвостовые поля, чтобы в словаре сетапа не было ключа с пустой строкой. -**Идемпотентность rename держится на токене `L<цифры>`.** `lap_token_present` — единственный источник истины для «уже обработан». Смена формата токена требует менять `insert_lap_token` и `lap_token_present` вместе, иначе rename перестаёт быть безопасным для повторного запуска. +**Идемпотентность rename держится на ДВУХ токенах.** Файл считается обработанным только при наличии обоих: токена типа сессии (`P1`, `Q2`, `R`, … — совпадение по `_SESSION_PAT`) и токена `L<цифры>`. `session_token_present` и `lap_token_present` — совместный источник истины. Смена формата любого токена требует обновить и функцию вставки, и функцию проверки одновременно. -**Отчёты выходят рядом с входом, а не рядом с программой.** `report_path` выводит папку `reports/` из папки *входного CSV*; режим `race` считает её от родителя папки гонки. Перемещение инструмента не меняет, куда попадают отчёты. +**Отчёты выходят рядом с входом, а не рядом с программой.** `report_path` выводит папку `reports/` из папки *входного CSV*. Режим `race` кладёт отчёт внутрь папки сессии (`/reports/`). Перемещение инструмента не меняет, куда попадают отчёты. diff --git a/README.md b/README.md index 13741fd..2c11302 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ Turns raw F1 22 lap telemetry into compact Markdown reports you can paste into a ```bash # from the tool/ folder -python -m telemetry technique ../zandvoort_P_L7_74.074_ferrari.csv -# -> ../reports/zandvoort_P_L7_74.074_ferrari_technique.md (~34k tokens) +python -m telemetry technique "races/Zandvoort/Practice/zandvoort_P1_L7_74.074_ferrari.csv" +# -> races/Zandvoort/Practice/reports/zandvoort_P1_L7_74.074_ferrari_technique.md (~35k tokens) ``` Or just double-click `run-gui.bat` and click **Generate report**. @@ -29,21 +29,27 @@ Five modes. Four produce reports, one renames files. | `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 | | `race` | a folder of laps | the whole race — pace, stint degradation, tyre wear, ERS per lap | -| `rename` | files/folder | insert the lap number into each filename (`..._74.074_...` → `..._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, so the LLM understands the data without extra prompting. Ready-made analysis prompts live in [`prompts/`](prompts/) — one per mode. +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. ### Folder layout -The program lives in `tool/`; your telemetry sits one level up, output lands next to it: - ``` Telemetry/ - zandvoort_P_L7_74.074_ferrari.csv <- raw laps here races/ - Zandvoort_Race_2026/ <- one folder per race (for `race` mode) - reports/ <- generated reports land here - tool/ <- this repository + Zandvoort/ + Practice/ <- CSVs go here after renaming + zandvoort_P1_L7_74.074_ferrari.csv + reports/ <- technique/setup/compare reports land here + Qualifying/ + zandvoort_Q1_L3_74.897_ferrari.csv + reports/ + Race/ + zandvoort_R_L7_74.152_ferrari.csv + reports/ + Race_race.md <- race mode report + tool/ <- this repository telemetry/ prompts/ run-gui.bat @@ -51,16 +57,19 @@ Telemetry/ ## Handy things -**GUI** — double-click `run-gui.bat` (or `run-gui.pyw` for no console window, or run `python -m telemetry gui`). Pick a mode, browse to the file/folder, click Generate. The **Rename unprocessed** button adds lap numbers to files that don't have them yet and leaves the rest alone. +**GUI** — double-click `run-gui.bat` (or `run-gui.pyw` for no console window, or run `python -m telemetry gui`). Pick a mode and language (RU/EN), browse to the file/folder, click Generate. The file browser remembers the last used directory per mode. The **Rename unprocessed** button adds the session type and lap number to files that don't have them yet and leaves the rest alone. **CLI** — from the `tool/` folder: ```bash -python -m telemetry technique ../lap.csv -python -m telemetry setup ../lap.csv -python -m telemetry compare ../lap_a.csv ../lap_b.csv -python -m telemetry race ../races/Zandvoort_Race_2026 -python -m telemetry rename ../races/Zandvoort_Race_2026 # or individual files +python -m telemetry technique 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 race races/Zandvoort/Race +python -m telemetry rename races/Zandvoort/Practice # or individual files + +# choose prompt language (default: ru) +python -m telemetry technique races/Zandvoort/Practice/lap.csv --lang en ``` Every report run prints the output path and a token estimate: @@ -70,7 +79,7 @@ C:\...\Telemetry\reports\lap_technique.md ~33834 tokens (budget 60k) ``` -**Rename only touches unprocessed files.** A file is "processed" once its name contains an `L` token, so re-running rename is safe and idempotent. +**Rename only touches unprocessed files.** A file is "processed" once its name contains both a session token (`P1`, `Q2`, `R`, …) and an `L` token. Re-running rename on the same folder is safe. ## Input format diff --git a/README.ru.md b/README.ru.md index 245f513..f7abdad 100644 --- a/README.ru.md +++ b/README.ru.md @@ -6,8 +6,8 @@ ```bash # из папки tool/ -python -m telemetry technique ../zandvoort_P_L7_74.074_ferrari.csv -# -> ../reports/zandvoort_P_L7_74.074_ferrari_technique.md (~34k токенов) +python -m telemetry technique "races/Zandvoort/Практика/zandvoort_P1_L7_74.074_ferrari.csv" +# -> races/Zandvoort/Практика/reports/zandvoort_P1_L7_74.074_ferrari_technique.md (~35k токенов) ``` Или просто двойной клик по `run-gui.bat` и кнопка **Generate report**. @@ -29,21 +29,27 @@ python -m telemetry technique ../zandvoort_P_L7_74.074_ferrari.csv | `setup` | один круг | **что** настроено — баланс (US/OS), температуры шин, тормоза, rake и крен подвески | | `compare` | два+ круга | **где** один круг быстрее — дельта по поворотам и накопленная | | `race` | папка кругов | вся гонка — темп, деградация в стинтах, износ резины, ERS по кругам | -| `rename` | файлы/папка | вставить номер круга в имя файла (`..._74.074_...` → `..._L7_74.074_...`) | +| `rename` | файлы/папка | вставить тип сессии и номер круга в имя файла (`..._74.074_...` → `..._P1_L7_74.074_...`) | -Отчёты содержат легенду с пояснением каждой колонки — LLM понимает данные без дополнительных подсказок. Готовые промпты для анализа лежат в [`prompts/`](prompts/) — по одному на режим. +Отчёты содержат легенду с пояснением каждой колонки, а промпт анализа добавляется в конец файла автоматически — достаточно скинуть файл в LLM. Промпты доступны на RU и EN; выбирается флагом `--lang en` в CLI или переключателем языка в GUI. ### Структура папок -Программа живёт в `tool/`; телеметрия — на уровень выше, отчёты выходят рядом с ней: - ``` Telemetry/ - zandvoort_P_L7_74.074_ferrari.csv <- сырые круги здесь races/ - Zandvoort_Race_2026/ <- по папке на гонку (для режима `race`) - reports/ <- сюда выходят отчёты - tool/ <- этот репозиторий + Zandvoort/ + Практика/ <- CSV-файлы после переименования + zandvoort_P1_L7_74.074_ferrari.csv + reports/ <- отчёты technique/setup/compare + Квалификация/ + zandvoort_Q1_L3_74.897_ferrari.csv + reports/ + Гонка/ + zandvoort_R_L7_74.152_ferrari.csv + reports/ + Гонка_race.md <- отчёт режима race + tool/ <- этот репозиторий telemetry/ prompts/ run-gui.bat @@ -51,16 +57,19 @@ Telemetry/ ## Полезное -**GUI** — двойной клик по `run-gui.bat` (или `run-gui.pyw` без окна консоли, либо `python -m telemetry gui`). Выбери режим, укажи файл/папку, нажми Generate. Кнопка **Rename unprocessed** добавляет номера круга к файлам, у которых их ещё нет, и не трогает остальные. +**GUI** — двойной клик по `run-gui.bat` (или `run-gui.pyw` без окна консоли, либо `python -m telemetry gui`). Выбери режим и язык промпта (RU/EN), укажи файл/папку, нажми Generate. Диалог открывается в последней использованной папке для каждого режима отдельно. Кнопка **Rename unprocessed** добавляет тип сессии и номер круга к файлам, у которых их ещё нет, и не трогает остальные. **CLI** — из папки `tool/`: ```bash -python -m telemetry technique ../lap.csv -python -m telemetry setup ../lap.csv -python -m telemetry compare ../lap_a.csv ../lap_b.csv -python -m telemetry race ../races/Zandvoort_Race_2026 -python -m telemetry rename ../races/Zandvoort_Race_2026 # или отдельные файлы +python -m telemetry technique 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 race races/Zandvoort/Гонка +python -m telemetry rename races/Zandvoort/Практика # или отдельные файлы + +# выбор языка промпта (по умолчанию: ru) +python -m telemetry technique races/Zandvoort/Практика/lap.csv --lang en ``` Каждый прогон печатает путь к отчёту и оценку токенов: @@ -70,7 +79,7 @@ C:\...\Telemetry\reports\lap_technique.md ~33834 tokens (budget 60k) ``` -**Rename трогает только необработанные файлы.** Файл считается обработанным, как только в имени появляется токен `L<номер>` — поэтому повторный запуск безопасен и идемпотентен. +**Rename трогает только необработанные файлы.** Файл считается обработанным, когда в имени есть оба токена: тип сессии (`P1`, `Q2`, `R`, …) и `L<номер>`. Повторный запуск безопасен. ## Входной формат