AAYMA
RU
Войти

WindPilot

Локальное приложение с веб-интерфейсом, REST API и CLI.

Рабочий MVP
Команда «WhesternUnion» 4💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: 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.md

WindPilot — прогнозирование мощности ВЭС

WindPilot — локальное приложение команды WhesternUnion для HackAlem. Система формирует почасовой прогноз нормализованной мощности двух ветровых турбин на 24 или 48 часов, проверяет качество исходных данных, сохраняет происхождение прогноза и предоставляет веб-интерфейс, REST API и команды для пакетных расчётов.

Численный прогноз рассчитывается локальной моделью машинного обучения. 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.

Далее:

  1. Разместите измерения согласно разделу «Исходные данные».
  2. Проверьте параметры .env. Для первого запуска OpenAI-ключ можно оставить пустым.
  3. Для архивного режима подготовьте data/weather_forecasts.csv согласно разделу о погодном архиве.
  4. Запустите сервер.
.venv\Scripts\python -m uvicorn wind_agent.api:app --host 127.0.0.1 --port 8000

Адреса:

НазначениеАдрес
Веб-интерфейсhttp://127.0.0.1:8000
Интерактивная документация APIhttp://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 расчётных моментов
Инициализация GFS12:00 UTC соответствующего дня
Момент расчёта в UTC18:00 UTC
Горизонт GFSf006–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.

Работа в веб-интерфейсе

  1. Откройте страницу приложения.
  2. Выберите турбину, источник погоды и горизонт 24 или 48 часов.
  3. Для исторического режима нажмите поле «Момент расчёта». Выберите день в календаре и час в списке временных слотов, затем примените выбор.
  4. Для подготовленного архива используйте 23:00 любого дня с 31 января по 28 февраля 2026 года. Для первого запуска — 31.01.2026, 23:00.
  5. При необходимости включите «Добавить OpenAI-анализ».
  6. Запустите расчёт и проверьте график, таблицу, предупреждения и журнал.
  7. Сохраните 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}/csvCSV выбранного запуска

Пример архивного расчёта через 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 представляет мгновенные значения на прогнозный час, тогда как мощность усредняется за час. Эти ограничения необходимо учитывать при интерпретации качества.

Проверка работоспособности

Рекомендуемый порядок проверки после установки или объединения изменений:

  1. Проверить аудит обеих турбин и фактические границы измерений.
  2. Проверить архив командой weather_download validate; при необходимости повторить с --decode-raw.
  3. Запустить автоматические тесты.
  4. Выполнить архивный прогноз на 31 января, 23:00 UTC+5, и убедиться, что он содержит 48 часов.
  5. Выполнить полный replay с явными границами из раздела CLI; проверить четыре отчёта и сохранение последнего горизонта до 2 марта.
  6. Проверить веб-интерфейс, экспорт 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; для воспроизводимой проверки происхождения необходимо сохранить весь комплект манифестов и оригиналов.

Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
11
Авторы
3
Файлы
35
Ветки
5

Авторы коммитов

azatich 5Azat 3Merey 3

История коммитов

  • 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 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.