О проекте
Команда: WhesternUnion
Кейс HackAlem.ai: Энергетика — Самрук-Казына
Стадия: Рабочий MVP
Задача кейса: AI-агент, прогнозирующий выработку ветровой электростанции по погодным данным
Суть
Локальное приложение с веб-интерфейсом, REST API и CLI. Оно даёт почасовой прогноз нормализованной мощности двух турбин на 24 или 48 часов по погодным данным, проверяет качество данных, делает исторический replay и оценивает ошибку.
Как устроено
10-минутные измерения агрегируются в часовые (не меньше 4 валидных точек), для каждой турбины обучается отдельная ML-модель. Погода берётся из трёх источников: инерционный baseline, архив оперативных прогнозов GFS (GRIB с сохранением метаданных публикации и SHA-256) и live Open-Meteo. Ежедневный replay считает MAE и RMSE по шагам горизонта и сравнивает с инерцией мощности. OpenAI через инструменты формулирует текстовый анализ прогноза и качества данных, но числовой прогноз от модели не зависит.
Ключевые решения
- почасовая агрегация и контроль пропусков
- отдельная модель на турбину
- архив GFS GRIB
- Open-Meteo live
- исторический replay без утечки будущего
- MAE/RMSE по шагам горизонта
- OpenAI tool calling для анализа
Особенности
Происхождение погодных данных проверяемо: хранятся исходные GRIB-сообщения, время публикации и SHA-256. Команда прямо пишет, что измерения заканчиваются 31 января, поэтому метрики за февраль равны null. Подготовлен архив из 2784 строк прогноза (29 дней × 48 ч × 2 турбины).
Стек
Python · FastAPI · Uvicorn · JavaScript · GitHub Actions · pytest
Модели
gpt-4.1-mini (OpenAI)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-ed0ebc3f-whesternunion.
README
README.mdWindPilot — прогнозирование мощности ВЭС
WindPilot — локальное приложение команды WhesternUnion для HackAlem. Система формирует почасовой прогноз нормализованной мощности двух ветровых турбин на 24 или 48 часов, проверяет качество исходных данных, сохраняет происхождение прогноза и предоставляет веб-интерфейс, REST API и команды для пакетных расчётов.
Численный прогноз рассчитывается локальной моделью машинного обучения. OpenAI подключается отдельно для текстового анализа результата и качества данных. Наличие API-ключа не является условием работы модели.
Содержание
- Возможности и текущие ограничения
- Установка и запуск
- Настройка .env
- Исходные данные
- Источники погоды и время расчёта
- Получение и проверка погодного архива
- Работа в веб-интерфейсе
- Команды CLI
- OpenAI-анализ
- API
- Результаты и интерпретация метрик
- Проверка работоспособности
- Устранение ошибок
- Структура проекта
Возможности и текущие ограничения
Реализованы:
- загрузка измерений обеих турбин, контроль пропусков и формирование часовых значений;
- отдельная модель мощности для каждой турбины;
- три источника погоды: инерционный прогноз, архив оперативных прогнозов GFS и текущий прогноз Open-Meteo;
- загрузчик GFS с сохранением исходных GRIB-сообщений, сведений о публикации и SHA-256;
- ежедневный исторический расчёт (replay) для обеих турбин и горизонтов 24/48 часов;
- оценка MAE/RMSE, метрики по шагам горизонта и сравнение с инерцией мощности при наличии фактических измерений;
- журнал расчёта, сохранение JSON, экспорт CSV и периодический режим
watch; - дополнительный OpenAI-анализ через инструменты проверки прогноза и качества данных.
В локальной сборке подготовлен погодный архив на 29 ежедневных расчётов с 31 января по 28 февраля 2026 года, по 48 часов для каждой турбины: 2784 строки. Архив и измерения не входят в Git и должны быть отдельно предоставлены на другом компьютере.
Предоставленные файлы измерений заканчиваются 31 января 2026 года, несмотря на дату 28 февраля в их названиях. Поэтому февральские прогнозы можно сформировать, но для оценки их точности необходимо получить фактическую мощность за февраль. Отсутствующие метрики обозначаются null.
Результат выражен в долях номинальной мощности от 0 до 1. Паспортная мощность турбин не задана, поэтому приложение не рассчитывает абсолютную мощность в МВт и энергию в МВт·ч.
Установка и запуск
Требования
Основной сценарий ниже предназначен для Windows PowerShell. Проект использует Python; проверенная среда разработки — Windows с Python 3.13. Node.js и сборка фронтенда для запуска не требуются.
Необходимы:
- Python и доступ к установке зависимостей из
requirements.txt; - исходные CSV выбранных турбин;
- доступ к интернету для установки пакетов, загрузки GFS, режима
liveи OpenAI; - около 4 ГБ свободного места для исходников полного GFS-архива, дополнительно к окружению и отчётам.
После установки зависимостей режимы baseline и archive работают без сети, если OpenAI-анализ отключён и нужные файлы уже находятся на диске.
Первичная установка
Все команды необходимо выполнять из корня проекта, где находятся README.md и requirements.txt.
cd C:\Home\hackalem\hack-ed0ebc3f-whesternunion
python -m venv .venv
.venv\Scripts\python -m pip install -r requirements.txt
if (-not (Test-Path .env)) { Copy-Item .env.example .env }
Если проект расположен в другом каталоге, замените путь в первой команде. Существующее окружение .venv повторно создавать не требуется. Условное копирование сохраняет уже заполненный .env.
Далее:
- Разместите измерения согласно разделу «Исходные данные».
- Проверьте параметры
.env. Для первого запуска OpenAI-ключ можно оставить пустым. - Для архивного режима подготовьте
data/weather_forecasts.csvсогласно разделу о погодном архиве. - Запустите сервер.
.venv\Scripts\python -m uvicorn wind_agent.api:app --host 127.0.0.1 --port 8000
Адреса:
| Назначение | Адрес |
|---|---|
| Веб-интерфейс | http://127.0.0.1:8000 |
| Интерактивная документация API | http://127.0.0.1:8000/docs |
| Состояние сервиса | http://127.0.0.1:8000/api/health |
Окно терминала должно оставаться открытым. Для остановки используется Ctrl+C. Для последующих запусков достаточно выполнить команду Uvicorn из корня проекта.
Активация виртуального окружения не обязательна: во всех примерах явно используется Python из .venv. В macOS/Linux соответствующий путь — .venv/bin/python.
Сервер запускается на локальном адресе. Встроенная авторизация пользователей не реализована.
Настройка .env
Файл .env находится в корне проекта, рядом с .env.example. Настройки загружаются при запуске процесса; после изменения необходимо перезапустить сервер или CLI-команду.
Пример конфигурации без подключённого OpenAI:
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4.1-mini
DATA_TIMEZONE=Etc/GMT-5
DATA_DIR=.
ARTIFACT_DIR=artifacts
TURBINE_1_LAT=43.645150
TURBINE_1_LON=78.535604
TURBINE_2_LAT=43.643198
TURBINE_2_LON=78.538828
| Параметр | Назначение |
|---|---|
OPENAI_API_KEY | Ключ OpenAI для дополнительного анализа. Вставляется после знака =; пустое значение отключает интеграцию. |
OPENAI_MODEL | Модель OpenAI; значение по умолчанию в приложении — gpt-4.1-mini. |
DATA_TIMEZONE | Часовой пояс измерений, если в CSV он не указан. Etc/GMT-5 означает фиксированный UTC+5. |
DATA_DIR | Каталог с CSV измерений. Точка означает текущий каталог запуска. |
ARTIFACT_DIR | Каталог сохранения прогнозов и отчётов replay. |
TURBINE_1_LAT, TURBINE_1_LON | Координаты первой турбины для live. |
TURBINE_2_LAT, TURBINE_2_LON | Координаты второй турбины для live. |
Относительные пути разрешаются относительно текущего рабочего каталога, поэтому команды следует выполнять из корня проекта. Переменные, уже установленные в окружении процесса, имеют приоритет над .env.
DATA_DIR относится только к измерениям. Веб-приложение всегда читает погодный архив из data/weather_forecasts.csv в корне проекта. Для CLI путь задаётся через --archive.
Загрузчик GFS использует фиксированные координаты задания, указанные выше. Переопределения координат в .env изменяют запросы live, но не координаты архивной загрузки.
Файл .env исключён из Git. API-ключ не следует помещать в README, исходный код, JavaScript или CSV.
Исходные данные
Размещение измерений
Вариант 1 — сохранить оригинальные файлы в корне проекта и оставить DATA_DIR=.:
Dataset HackAlemAI для участников 11.03.2023-28.02.2026 - turbine 1.csv
Dataset HackAlemAI для участников 11.03.2023-28.02.2026 - turbine 2.csv
Вариант 2 — разместить файлы с каноническими названиями в отдельном каталоге:
data/observations/turbine_1.csv
data/observations/turbine_2.csv
Для второго варианта укажите:
DATA_DIR=data/observations
Канонический файл turbine_1.csv или turbine_2.csv имеет приоритет. Если его нет, загрузчик ищет единственный файл, оканчивающийся на turbine 1.csv или turbine 2.csv. Несколько подходящих файлов в одном каталоге создают неоднозначность.
Оригинальные файлы с префиксом Dataset и весь каталог data/ исключены из Git. Произвольный CSV в корне, включая turbine_1.csv, автоматически этим правилом не исключается.
Формат и проверка
Используются UTF-8, запятая как разделитель и точка как десятичный разделитель.
| Канонический столбец | Поддерживаемое исходное название | Значение |
|---|---|---|
timestamp | Статистическое время | Время измерения |
wind_speed | Средняя скорость ветра(m/s) | Скорость ветра, м/с |
power | Нормализованная активная мощность | Нормализованная мощность, 0–1 |
temperature | Средняя температура окружающей среды(°C) | Температура, °C |
Пример структуры строки; это иллюстрация формата, а не готовый набор данных:
timestamp,wind_speed,power,temperature
2026-01-31 23:00:00,6.7,0.24,1.5
Для обоих форматов предполагается 10-минутный шаг. Часовое среднее принимается при наличии минимум четырёх валидных уникальных измерений. Дубли времени удаляются с сохранением первой строки. Нечисловые значения и значения вне диапазонов ветер 0–75 м/с, температура −80…65 °C, мощность 0–1 исключаются из пригодных измерений. Недостаточно заполненные часы не восстанавливаются по будущим данным.
Для обучения требуется не менее 240 пригодных часовых наблюдений. При расчёте на исторический момент учитываются только завершившиеся к этому времени часы.
Фиксированный UTC+5 для исходных дат без часового пояса является допущением, требующим подтверждения у поставщика данных, особенно для старой части истории. Внутренние временные метки и экспорт приводятся к UTC.
Источники погоды и время расчёта
origin — момент, на который формируется прогноз мощности. Горизонт 48 часов содержит интервалы с начала origin до origin + 47 часов включительно.
| Режим | Источник | Применение |
|---|---|---|
baseline | Средние ветер и температура последних шести пригодных часовых наблюдений, распространённые на весь горизонт | Локальная проверка работы; внешнего прогноза погоды нет |
archive | Ранее опубликованный оперативный прогноз из CSV | Воспроизведение исторических расчётов без доступа к будущему |
live | Текущий прогноз Open-Meteo: ветер на 100 м и температура на 2 м | Прогноз на ближайшие часы относительно текущего времени |
В режиме baseline модель получает одинаковую погоду на каждом шаге, поэтому постоянная линия мощности является ожидаемым результатом. Если последние завершённые наблюдения старше шести часов относительно origin, расчёт отклоняется.
Режим archive выбирает один наиболее свежий выпуск, который полностью покрывает горизонт и удовлетворяет issued_at <= origin и available_at <= origin. Фактическая будущая погода, реанализ и hindcast не принимаются вместо исторического оперативного прогноза.
В режиме live момент расчёта определяется автоматически как следующий полный час UTC после получения погоды; переданный origin не используется. Этот режим не предназначен для воспроизведения февраля 2026 года.
Согласованное расписание архива
| Параметр | Значение |
|---|---|
| Первый расчёт мощности | 31 января 2026, 23:00 UTC+5 |
| Последний расчёт мощности | 28 февраля 2026, 23:00 UTC+5 |
| Периодичность | Ежедневно, всего 29 расчётных моментов |
| Инициализация GFS | 12:00 UTC соответствующего дня |
| Момент расчёта в UTC | 18:00 UTC |
| Горизонт GFS | f006–f053, 48 почасовых значений |
| Последний прогнозируемый час | 2 марта 2026, 22:00 UTC+5 |
Время инициализации погодной модели, время доступности файлов и момент расчёта мощности — отдельные поля. Их нельзя заменять друг другом.
В текущем CLI значение backtest --start по умолчанию — 31 января, 00:00 UTC+5. Оно не соответствует расписанию подготовленного архива. Для этого архива необходимо явно задавать даты из примера replay ниже. В обычном историческом forecast без --origin используется 1 февраля, 00:00 UTC+5; архивный пример также требует явного времени 23:00.
Получение и проверка погодного архива
Если архив уже предоставлен, для расчёта достаточно data/weather_forecasts.csv. Для проверки происхождения требуется также data/weather_forecasts.manifest.json и каталог data/raw/gfs/.
Для самостоятельной загрузки:
.venv\Scripts\python -m pip install -r requirements-weather.txt
.venv\Scripts\python -m wind_agent.weather_download fetch --workers 6
.venv\Scripts\python -m wind_agent.weather_download validate
По умолчанию загружается весь согласованный период для обеих турбин. Ключи OpenAI и AWS не требуются. Используется публичный оперативный архив NOAA GFS noaa-gfs-bdp-pds, сетка 0,25°. Зависимость eccodes нужна для загрузки с декодированием GRIB и дополнительной проверки --decode-raw; чтение готового погодного CSV её не требует.
Повторное независимое декодирование сохранённых оригиналов:
.venv\Scripts\python -m wind_agent.weather_download validate --decode-raw
Параметры загрузчика:
| Параметр | Назначение |
|---|---|
--first-origin | Первый ежедневный расчёт включительно; по умолчанию 2026-01-31T23:00:00+05:00 |
--last-origin | Последний расчёт включительно; по умолчанию 2026-02-28T23:00:00+05:00 |
--output | Итоговый CSV; по умолчанию data/weather_forecasts.csv |
--raw-dir | Каталог оригиналов; по умолчанию data/raw/gfs |
--workers | Число параллельных загрузок для fetch, от 1 до 12 |
Для проверки одного дня без замены основного CSV:
.venv\Scripts\python -m wind_agent.weather_download fetch --last-origin 2026-01-31T23:00:00+05:00 --output data/weather_smoke.csv
.venv\Scripts\python -m wind_agent.weather_download validate --last-origin 2026-01-31T23:00:00+05:00 --output data/weather_smoke.csv
Загрузчик сохраняет исходные GRIB-сообщения, извлечённые диапазонными HTTP-запросами, полные индексы, HTTP-заголовки и JSON-манифесты. SHA-256 связывает исходники с итоговым CSV. При повторном запуске проверенный кеш используется для продолжения загрузки. Ошибки содержимого, неполный горизонт и неподтверждённая доступность приводят к отказу; предыдущий успешный CSV сохраняется.
available_at определяется по максимальному времени Last-Modified всех требуемых объектов и индексов выпуска. Загрузчик отклоняет неподдерживаемые схемы ETag и multipart, проверяет, что файлы существовали не позже origin, и отдельно сохраняет время текущего получения. Это подтверждение времени записи объектов публичного архива; отдельные исторические журналы доступа и самое раннее распространение NOAA по другим каналам не проверяются.
Контракт CSV неизменен:
turbine,issued_at,available_at,valid_time,wind_speed,temperature,source,kind
Все три времени должны содержать часовой пояс; kind=forecast, ветер — в м/с, температура — в °C. Ветер получается из компонентов U/V на 100 м после пространственной интерполяции, температура на 2 м переводится из K в °C. Временная интерполяция не применяется.
Полные правила, происхождение, ограничения подтверждения публикации и сведения о проверенной локальной сборке приведены в docs/weather-contract.md.
Работа в веб-интерфейсе
- Откройте страницу приложения.
- Выберите турбину, источник погоды и горизонт 24 или 48 часов.
- Для исторического режима нажмите поле «Момент расчёта». Выберите день в календаре и час в списке временных слотов, затем примените выбор.
- Для подготовленного архива используйте 23:00 любого дня с 31 января по 28 февраля 2026 года. Для первого запуска — 31.01.2026, 23:00.
- При необходимости включите «Добавить OpenAI-анализ».
- Запустите расчёт и проверьте график, таблицу, предупреждения и журнал.
- Сохраните CSV через кнопку экспорта.
Календарь использует фиксированный UTC+5; графики и временные метки результата представлены в UTC. Настройка DATA_TIMEZONE не изменяет часовой пояс календаря. В режиме live ручной выбор времени отключён.
При открытии панель показывает последний сохранённый расчёт, если он есть. Это может быть исторический результат. Для получения нового прогноза необходимо запустить новый расчёт. Если сохранённых запусков нет, выполняется начальный расчёт baseline без OpenAI.
Запуск веб-сервера не включает периодический пересчёт. Для него предусмотрена отдельная команда watch.
Команды CLI
Аудит измерений
.venv\Scripts\python -m wind_agent audit --turbine 1
.venv\Scripts\python -m wind_agent audit --turbine 2
Отчёт содержит характеристики исходного файла, временное покрытие, количество пригодных часов и сведения о пропусках.
Одиночный прогноз
Проверка без внешней погоды:
.venv\Scripts\python -m wind_agent forecast --turbine 1 --mode baseline --horizon 48 --origin 2026-01-31T23:00:00+05:00
Исторический расчёт по архиву:
.venv\Scripts\python -m wind_agent forecast --turbine 1 --mode archive --archive data/weather_forecasts.csv --horizon 48 --origin 2026-01-31T23:00:00+05:00
Текущий прогноз для второй турбины:
.venv\Scripts\python -m wind_agent forecast --turbine 2 --mode live --horizon 24
Параметр --ai добавляет OpenAI-анализ. Без него платные запросы OpenAI не выполняются. CLI выводит идентификатор и сводку, а полный результат сохраняет в ARTIFACT_DIR/runs/.
Полный replay за февраль
Replay последовательно воспроизводит ежедневные расчёты на исторические моменты. Для подготовленного архива используйте команду со всеми временными границами:
.venv\Scripts\python -m wind_agent backtest --archive data/weather_forecasts.csv --turbine all --horizon both --start 2026-01-31T23:00:00+05:00 --end 2026-03-01T00:00:00+05:00 --score-start 2026-02-01T00:00:00+05:00
Команда формирует четыре отчёта: две турбины × два горизонта. Для одной турбины или горизонта замените all на 1/2 и both на 24/48.
--startзадаёт первый момент расчёта; следующий наступает через 24 часа.--end— исключительная верхняя граница моментов расчёта и окна оценки.--score-startограничивает начало оценки 1 февраля, исключая январские факты из февральских метрик.- Все часы последнего прогноза сохраняются, в том числе часы марта. Метрики рассчитываются только внутри окна оценки и при наличии факта.
- Перекрывающиеся часы разных выпусков оцениваются отдельно для каждого прогноза.
- OpenAI при replay не вызывается.
При полном архиве ожидаются 29 выпусков на отчёт: 696 строк для горизонта 24 часа и 1392 строки для горизонта 48 часов. Отчёты сохраняются в ARTIFACT_DIR/backtest-t<турбина>-<идентификатор>.json и .csv; пути выводятся в результате команды.
Периодический расчёт
.venv\Scripts\python -m wind_agent watch --turbine 1 --mode live --horizon 48 --interval 3600
Интервал задаётся в секундах, минимум — 60. Процесс работает до остановки Ctrl+C. При временной ошибке предусмотрены повторные попытки с увеличением задержки; при неизменных входах новый отчёт и повторный AI-анализ не создаются.
watch не устанавливает службу операционной системы. Архивный режим требует --archive и подходящего --origin; автоматическое продвижение по историческим датам выполняется командой backtest.
Справка по параметрам:
.venv\Scripts\python -m wind_agent --help
.venv\Scripts\python -m wind_agent backtest --help
.venv\Scripts\python -m wind_agent.weather_download --help
OpenAI-анализ
Для подключения вставьте действующий ключ в .env после OPENAI_API_KEY=, без угловых скобок и поясняющего текста. При необходимости измените OPENAI_MODEL на доступную вашему API-проекту модель с поддержкой Responses API и вызова инструментов. Перезапустите сервер, обновите страницу, включите флажок анализа и выполните новый расчёт.
Интеграция использует два инструмента:
| Инструмент | Содержание |
|---|---|
inspect_forecast | Сводка прогноза, источник погоды, режим и предупреждения |
inspect_data_quality | Качество измерений и результаты валидации модели |
Передаются сводные данные и метаданные происхождения; исходные CSV целиком не отправляются. OpenAI формирует объяснение после численного расчёта. Выбор погодного источника, подготовка данных и обучение модели выполняются кодом приложения.
Один анализ ограничен четырьмя логическими запросами Responses API, до 600 выходных токенов на запрос. SDK может повторить неудачный запрос. Ограничение числа запросов не является денежным лимитом аккаунта.
ai.status | Значение |
|---|---|
not_requested | Анализ не был включён |
disabled | Ключ не настроен |
complete | Получен текст после проверки обоих инструментов |
incomplete | Проверка обоих источников или итоговый ответ не завершены |
unavailable | Ошибка доступа к OpenAI, модели, лимитов или сети |
budget_limit | Достигнуто ограничение четырёх логических запросов |
Поле openai_configured=true в /api/health означает только наличие непустого значения ключа. Оно не подтверждает его действительность, доступ к модели или наличие средств. При ошибке OpenAI численный результат сохраняется; подробности исключения провайдера в отчёт не записываются.
API
| Метод и путь | Назначение |
|---|---|
GET /api/health | Состояние сервиса, часовой пояс, наличие настройки OpenAI |
GET /api/datasets | Сведения о качестве данных двух турбин |
POST /api/forecast | Новый расчёт |
GET /api/runs | Последние 20 сохранённых запусков |
GET /api/runs/{run_id} | Полный JSON выбранного запуска |
GET /api/runs/{run_id}/csv | CSV выбранного запуска |
Пример архивного расчёта через PowerShell при запущенном сервере:
$forecastBody = @{
turbine = 1
horizon = 48
mode = "archive"
origin = "2026-01-31T23:00:00+05:00"
use_ai = $false
} | ConvertTo-Json
$forecastResult = Invoke-RestMethod -Uri "http://127.0.0.1:8000/api/forecast" -Method Post -ContentType "application/json" -Body $forecastBody
$forecastResult.summary
$forecastResult.id
Допустимы турбины 1/2, горизонты 24/48 и режимы baseline/archive/live. В историческом режиме передавайте origin в ISO 8601 с часовым поясом. Ошибка проверки данных возвращается как HTTP 422; ошибка получения внешней погоды — как HTTP 502.
Результаты и интерпретация метрик
Полный прогноз сохраняется в artifacts/runs/<id>.json, если ARTIFACT_DIR не переопределён.
| Поле | Содержание |
|---|---|
origin, horizon, turbine, mode | Параметры расчёта |
training_cutoff, model | Граница обучающих данных и версия модели |
quality, validation | Качество исходных данных и хронологическая проверка модели |
weather | Происхождение погоды, временные границы и доступные контрольные суммы |
forecast | Все почасовые значения прогноза |
summary | Средняя и максимальная мощность, ветер и другие агрегаты |
warnings, trace | Ограничения и журнал этапов |
ai | Статус и текст дополнительного анализа |
equivalent_full_load_hours — сумма почасовой нормализованной мощности, выраженная в эквивалентных часах полной нагрузки. Для перевода в МВт·ч необходима номинальная мощность соответствующей турбины в МВт.
Обучение и валидация
Базовая модель — HistGradientBoostingRegressor, отдельно для каждой турбины, с признаками ветра, куба скорости ветра и температуры. Хронологическое разделение 80/20 применяется для проверки, после чего модель обучается на всей допустимой истории.
Граница обучения — более ранний момент из origin и 1 февраля 2026, 00:00 в DATA_TIMEZONE. Это ограничение задано в коде и действует также для live; добавление февральских фактов само по себе не включает их в обучение.
В архивном режиме предусмотрена модель на парных исторических прогнозах погоды и фактической мощности. Она требует достаточного количества уникальных часов и покрытия заблаговременности до границы обучения. Архива, начинающегося 31 января, недостаточно для такого обучения на имеющихся измерениях. В этом случае применяется базовая модель и выводится предупреждение.
Значение validation.scope определяет смысл метрик:
power_curve_on_observed_weather— проверка модели мощности на измеренной погоде;power_on_archived_forecast_weather— проверка на исторических прогнозах погоды обучающего периода.
Эти показатели не являются результатом февральского replay. Февральские MAE/RMSE находятся в полях metrics отчёта backtest и требуют фактических измерений за соответствующие часы.
Сравнение и неопределённость
MAE — средняя абсолютная ошибка, RMSE — среднеквадратическая ошибка; обе метрики выражены в долях номинальной мощности. Например, MAE 0,05 означает среднюю абсолютную ошибку в пять процентных пунктов нормализованной мощности.
metrics_by_lead показывает ошибки по шагам от 0 до 23 или 47 часов относительно origin. baseline_comparison сравнивает модель со средней мощностью за шесть часов перед расчётом при наличии минимум четырёх пригодных часов. Сравниваются только одинаковые строки с доступными фактом и baseline. Это отдельный эталон сравнения, отличающийся от погодного режима baseline.
Диапазон на графике построен по ошибкам валидации и является диагностической полосой. Он не является калиброванным вероятностным интервалом; у базовой модели он не учитывает ошибку прогноза погоды.
Высота датчика исходного ветра неизвестна; ветер GFS/Open-Meteo на 100 м не откалиброван к измерениям турбин. GFS представляет мгновенные значения на прогнозный час, тогда как мощность усредняется за час. Эти ограничения необходимо учитывать при интерпретации качества.
Проверка работоспособности
Рекомендуемый порядок проверки после установки или объединения изменений:
- Проверить аудит обеих турбин и фактические границы измерений.
- Проверить архив командой
weather_download validate; при необходимости повторить с--decode-raw. - Запустить автоматические тесты.
- Выполнить архивный прогноз на 31 января, 23:00 UTC+5, и убедиться, что он содержит 48 часов.
- Выполнить полный replay с явными границами из раздела CLI; проверить четыре отчёта и сохранение последнего горизонта до 2 марта.
- Проверить веб-интерфейс, экспорт CSV и при необходимости отдельный запрос OpenAI.
Команда тестов:
.venv\Scripts\python -m pytest -q
Тесты охватывают подготовку данных, временные границы, выбор архивного выпуска, модель, replay, API/CSV и агентный анализ с имитацией ответов OpenAI. Тесты с имитацией не подтверждают доступность реального API-ключа.
При отсутствии февральских фактов ожидаются scored_predictions=0 и metrics=null. Наличие прогнозов и успешный запуск тестов сами по себе не подтверждают точность прогноза на февраль.
Устранение ошибок
| Симптом | Причина и действие |
|---|---|
WinError 10048, порт 8000 занят | На этом порту уже работает процесс. Проверьте существующий сервер либо запустите приложение на другом порту командой ниже. |
| CSV не найден | Проверьте DATA_DIR, имена файлов и запуск из корня проекта. После изменения .env перезапустите процесс. |
| Найдено несколько CSV для одной турбины | Оставьте один исходный файл в каталоге данных либо используйте однозначное каноническое имя. |
| Недостаточно истории для обучения | Проверьте наличие минимум 240 пригодных часов до границы обучения, названия столбцов, единицы и пропуски. |
| «Последние наблюдения старше 6 часов» | Для выбранного origin режим baseline не располагает свежими наблюдениями. Выберите момент рядом с концом измерений либо используйте архивный или текущий прогноз погоды. |
| «Нет полного архивного прогноза, доступного на момент расчёта» | Проверьте наличие CSV, турбину, полный горизонт и время. Для готового архива используйте 23:00 UTC+5 с 31 января по 28 февраля. Не изменяйте available_at для обхода проверки. |
| Replay не запускается с параметрами по умолчанию | Задайте --start 2026-01-31T23:00:00+05:00, --end и --score-start из приведённого примера. |
live возвращает ошибку погоды / HTTP 502 | Проверьте интернет, доступ к Open-Meteo и координаты. Повторите запрос; для периодических расчётов используйте watch. |
Не найден eccodes или не открывается GRIB | Установите requirements-weather.txt именно через Python из .venv. Эта зависимость нужна загрузчику, но не готовому CSV. |
| Ошибка SHA-256 или публикации GFS | Исходники не прошли проверку. Сохраните сообщение ошибки; для независимой загрузки используйте отдельные --raw-dir и --output. Не исправляйте контрольные суммы вручную. |
| Флажок OpenAI недоступен | Проверьте непустой OPENAI_API_KEY в корневом .env, перезапустите сервер и обновите страницу. Проверьте openai_configured через /api/health. |
Ключ указан, но ai.status=unavailable | Проверьте действительность ключа, доступ к указанной модели, лимиты API-проекта и сеть. Наличие кредитов не заменяет эти проверки. |
Изменения .env не применяются | Перезапустите процесс. Также проверьте, не установлена ли одноимённая переменная в окружении терминала: она имеет приоритет. |
| График остаётся прежним после открытия страницы | Панель могла загрузить сохранённый запуск. Выберите параметры и выполните новый расчёт. |
| Время отличается на пять часов | Календарь использует UTC+5, а результат — UTC. Например, 23:00 UTC+5 соответствует 18:00 UTC. |
| Нет февральских метрик | В текущих измерениях нет февральского факта. Предоставьте реальные измерения; вымышленные значения не используются. |
Запуск на свободном порту:
.venv\Scripts\python -m uvicorn wind_agent.api:app --host 127.0.0.1 --port 8001
После этого откройте http://127.0.0.1:8001. Для изменения существующего запуска остановите его через Ctrl+C в соответствующем терминале.
Структура проекта
wind_agent/
config.py Настройки окружения, координаты и граница обучения
data.py Поиск, проверка и часовая агрегация измерений
model.py Обучение моделей и прогноз мощности
weather.py Baseline, архивный и текущий погодные адаптеры
weather_download.py Загрузка GFS, происхождение, SHA-256 и проверка архива
service.py Расчёт, сохранение результатов и исторический replay
agent.py Дополнительный OpenAI-анализ
api.py FastAPI и выдача веб-интерфейса
__main__.py CLI: audit, forecast, backtest, watch
web/ HTML, CSS, JavaScript и календарь выбора времени
tests/ Автоматические тесты
docs/
weather-contract.md Контракт и происхождение погодного архива
architecture.md Дополнительное описание архитектуры
data/ Локальные данные и погодный архив; исключены из Git
artifacts/ Результаты расчётов; исключены из Git
.env.example Шаблон конфигурации
requirements.txt Основные зависимости
requirements-weather.txt Дополнительная зависимость для GRIB
Измерения, погодный архив, исходные GRIB и .env передаются отдельно от репозитория. Для обычного расчёта по архиву достаточно измерений и погодного CSV; для воспроизводимой проверки происхождения необходимо сохранить весь комплект манифестов и оригиналов.
Авторы коммитов
История коммитов
- 2026-09-23 17:56Merge pull request #4 from BAITC-Hacks/fix2azatich
- 2026-09-23 17:56Merge branch 'main' into fix2azatich
- 2026-09-23 17:55fixAzat
- 2026-09-23 17:07readMerey
- 2026-09-23 16:53Merge pull request #3 from BAITC-Hacks/fixazatich
- 2026-09-23 16:52Merge pull request #2 from BAITC-Hacks/feature/mereyazatich
- 2026-09-23 16:51second tryMerey
- 2026-09-23 16:35foxAzat
Все коммиты (11)
- 2026-09-23 15:39Merge pull request #1 from BAITC-Hacks/feature/mereyazatich
- 2026-09-23 15:37first tryMerey
- 2026-09-23 12:01testing gitAzat
Структура репозитория (35 файлов)
.env.example .github/workflows/tests.yml .gitignore README.md docs/architecture.md docs/demo.md docs/evaluation.md docs/weather-contract.md requirements-weather.txt requirements.txt tests/conftest.py tests/test_agent.py tests/test_cli.py tests/test_data.py tests/test_model.py tests/test_pipeline.py tests/test_weather.py tests/test_workflow.py web/app.js web/index.html web/origin-picker.css web/origin-picker.js web/style.css wind_agent/__init__.py wind_agent/__main__.py wind_agent/agent.py wind_agent/api.py wind_agent/config.py wind_agent/data.py wind_agent/model.py wind_agent/schedule.py wind_agent/service.py wind_agent/weather.py wind_agent/weather_download.py wind_agent/workflow.py
Ветки (5)
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.