Всім привіт! Я, як і багато хто тут, не тільки розробник, але й людина, захоплена циклічними видами спорту. Я обожнюю копирсатися в даних своїх тренувань з Strava: аналізувати потужність, пульсові зони, темп. Але мені завжди не вистачало однієї речі — єдиної, зрозумілої і, головне, прозорої метрики, яка б відповідала на просте питання: "А наскільки я зараз в хорошій формі?".
Звичайно, є VO2max, є Fitness & Freshness від Strava, є GFR у Garmin. Але мені завжди хотілося створити щось своє. Метрику, яку я б розумів від і до, від першої стрічки коду до фінальної цифри на екрані.
Так в рамках мого pet-проекту The Peakline цієї платформи для аутдор-ентузіастів народилася ідея PeakLine Score (PLS). Це моя спроба створити комплексну оцінку продуктивності, яка враховує не тільки твою швидкість, але й складність маршруту, по якому ти їхав.
У цій статті я розповім, як влаштований цей механізм "під капотом". Ми зануримося в логіку на Python, подивимося, як вона інтегрується в загальний аналізатор активностей і як результат подається користувачеві в простому і зрозумілому вигляді.
Важливий дисклеймер: Весь проект, від ідеї до коду, я роблю один у вільний від основної роботи час. Він далекий від ідеалу, і я буду дуже вдячний за конструктивну критику і свіжий погляд.
Запрошую вас вивчити сам проект:
- Основний проект The Peakline: https://www.thepeakline.com/
- Репозиторій на GitHub: https://github.com/CyberScoper/peakline-peakline-score
- Демо сторінки зі Score: https://www.thepeakline.com/peakline-score (необхідна авторизація в акаунт Strava)
А тепер — до технічних деталей.
Загальний вигляд сторінки PeakLine Score
Архітектура: Python-мозок і HTML-обличчя
Коли ти робиш проект самотужки, простота і чітке розділення відповідальності — ключ до виживання. Я не став ускладнювати і побудував архітектуру за класичною схемою: бекенд на Python (Flask) відповідає за всю логіку, а фронтенд — це легковаговий HTML, відмальований за допомогою серверного шаблонізатора Jinja2.
Щоб не потонути в коді, я розділив логіку PLS на три чітких, незалежних компоненти:
peakline_score.py
(Мозок): Чистий Python-модуль, ядро всієї системи. Він нічого не знає про Strava, веб-сервери чи бази даних. Його завдання — прийняти на вхід числові дані про активність і повернути числовий бал. Максимально ізольований і тестовий.activity_analyzer.py
(Інтегратор): Цей модуль — диригент оркестру. Він забирає "сирі" дані з Strava, проводить їх через різні аналізатори (розрахунок зон потужності, пульсу) і, в тому числі, передає їх вpeakline_score.py
для розрахунку PLS. Його завдання — елегантно вбудувати нову фічу в існуючий конвеєр.peakline_score.html
(Обличчя): Jinja2-шаблон. Він отримує з бекенду готовий словник з даними PLS і відповідає тільки за те, щоб красиво і зрозуміло їх показати користувачеві.
Такий підхід дозволяє мені легко доопрацьовувати кожен компонент окремо.
peakline_score.py: Математика "супер-атлета"
Це серце всієї системи. Як об'єктивно оцінити результат? Проїхати 100 км по плоскій трасі за 3 години — це одне, а проїхати 70 км з набором висоти 2000 метрів за той же час — зовсім інше.
Ідея проста: а що, якщо порівняти час користувача з часом, який показав би на цьому ж маршруті гіпотетичний "ідеальний" спортсмен?
Спочатку я визначив параметри цього "супер-атлета" — константний об'єкт з показниками атлета світового рівня.
Потім я написав функцію calculateideal_time
, яка оцінює, за скільки б цей "супер-атлет" проїхав маршрут. Логіка враховує два ключових фактори: час на рівнині і "штраф" за набір висоти.
Функція getterrain_coefficient
додатково класифікує маршрут (flat
, rolling
, hilly
, mountain
) і вводить невеликий підвищувальний коефіцієнт для складнішого рельєфу.
Тепер, маючи actual_time
і ideal_time
, формула розрахунку балу стає елементарною:
pls_points = (ideal_time / actual_time) * 1000
Якщо проїхав як "супер-атлет" — отримуєш 1000 балів. Вдвічі повільніше — 500. Просто і прозоро.
activity_analyzer.py: Інтеграція без болю
Нова фіча не повинна ламати стару логіку. У мене вже був великий модуль activity_analyzer.py
, який виконував повний аналіз тренування: запитував дані з Strava, рахував зони потужності, пульсу, отримував погоду. Завдання — вбудувати розрахунок PLS в цей процес, не створюючи хаосу.
Я вирішив цю задачу за допомогою невеликої допоміжної функції add_pls_to_activity_analysis
. Вона працює як останній крок в конвеєрі аналізу.
Сама функція-обгортка add_pls_to_activity_analysis
просто витягує вже пораховані дані з загального об'єкта аналізу, передає їх в наш калькулятор PeakLineScoreCalculator
і додає результат в новий ключ peakline_score
.
Такий підхід "декоратора" дозволив додати нову складну логіку, практично не змінюючи основний код аналізатора.
peakline_score.html: Від цифр до емоцій
Сухі цифри на бекенді — це лише половина справи. Важливо було подати їх користувачеві так, щоб це мотивувало, а не засмучувало. Тут в гру вступає шаблонізатор Jinja2.
Бекенд передає в шаблон один великий об'єкт pls_data
. А далі магія відбувається прямо в HTML. Наприклад, головний бал виводиться однією стрічкою:
Таблиця з найкращими результатами генерується в циклі, що робить код чистим і лаконічним:
А блок з рекомендаціями використовує просту if/elif/else
логіку, щоб давати різні поради залежно від рівня користувача. Це робить сторінку "живою" і персоналізованою.
Під капотом "Загального рейтингу": Як з хаосу тренувань народжується єдиний бал
Найцікавіша частина — це не оцінка однієї тренування, а обчислення загального рейтингу атлета. Адже одна випадкова супер-успішна гонка не повинна визначати весь його рівень. Тут я підгледів ідею у Garmin з їх GFR Score, але реалізував її по-своєму.
Алгоритм в функції calculate_user_pls_score
складається з п'яти простих кроків:
- Аналіз: Скрипт перебирає всі доступні тренування користувача.
- Розрахунок: Для кожної обчислюється індивідуальний PLS-бал.
- Сортування: Всі результати сортуються за спаданням — від найкращих до найгірших.
- Вибірка: З усього списку беруться тільки 6 найкращих результатів. Це дозволяє відсіяти невдалі або відновлювальні тренування, які не відображають пікову форму.
- Усереднення: Ітоговий PeakLine Score — це просте середнє арифметичне цих шести найкращих показників.
Ось як це виглядає в коді:
Цей підхід здався мені найбільш збалансованим. Він відображає реальний потенціал, але при цьому достатньо стабільний і не скаче від однієї невдалої тренування.
Таблиця найкращих результатів, основа для розрахунку загального балу.
Труднощі на шляху соло-розробника
Коли ти один на один з проектом, проблеми набувають особливого смаку.
- Підбір коефіцієнтів. Найскладнішим було знайти "правильні" цифри для
SUPER_ATHLETE_PARAMS
і "штрафів" за рельєф. Я витратив кілька вечорів, порівнюючи свої результати з результатами професіоналів на відомих сегментах Strava. Це була справжня дослідницька робота, щоб досягти адекватної і правдоподібної оцінки. - "Брудні" дані з API. Не у всіх активностях є дані про набір висоти. Іноді GPS-трек може бути неточним. Довелося закласти в код безліч перевірок на кшталт
details.get('total_elevation_gain', 0)
, щоб одна "зламана" тренування не обвалила весь аналіз користувача. - Зробити фічу мотивуючою. Спочатку шкала була надто жорсткою, і більшість користувачів отримували б "образливі" 300-400 балів. Я зрозумів, що продукт повинен надихати. Тому я доопрацював формулу і додав текстові рівні (
'Elite'
,'Excellent'
,'Good'
), а також той самий блок з рекомендаціями, щоб система не просто ставила оцінку, а підказувала, як стати кращим.
Що далі? Плани розвитку
PeakLine Score — це тільки початок. У мене в планах:
- Врахування більшої кількості факторів: Додати в формулу вплив погоди (вітер, температура), дані про яку я вже отримую для детального аналізу активності.
- Динаміка в часі: Будувати графік зміни PLS, щоб користувач бачив свій прогрес наочно.
- Розділення за видами спорту: Створити окремі рейтинги для бігу і велоспорту, так як порівнювати їх безпосередньо некоректно.
Висновок і заклик до дій
Створення своєї власної аналітичної метрики — це захоплююча подорож на стику програмування і предметної області (в моєму випадку — спорту). PeakLine Score — це моя перша спроба зробити щось подібне, і я впевнений, що формулу ще можна і потрібно покращувати.
І тут мені дуже потрібна ваша допомога.
Заклик №1: Оцініть ідею. Як вам сама концепція? Які фактори ви б додали в розрахунок? Може, у вас є ідеї, як зробити оцінку ще точнішою і кориснішою?
Заклик №2: Поділіться своєю думкою. Мені дуже важливо почути вашу думку про проект The Peakline в цілому. Чи потрібні такі нішеві інструменти для спортсменів-аматорів?
Дякую, що дочитали цю довгу статтю. Буду радий будь-якому фідбеку в коментарях!
Коментарі