О проекте
Команда: KU group
Кейс HackAlem.ai: Энергетика — Самрук-Казына
Стадия: Доведённый продукт
Задача кейса: AI-агент, прогнозирующий выработку ветровой электростанции по погодным данным
Суть
Агентная система почасового прогноза выработки ВЭС на 48 часов с интервалами p10/p50/p90. Прогноз строится по архивным прогнозам погоды семи моделей Open-Meteo. Есть журнал агента в реальном времени, паспорт выпуска и сравнение с предыдущим выпуском.
Как устроено
На истории двух турбин при старте обучается HistGradientBoostingRegressor с квантильной функцией потерь и конформной калибровкой интервалов. Агент с 7 инструментами выбирает источники погоды через Open-Meteo Previous Runs и берёт только выпуски NWP, опубликованные до момента решения (задержка 7 ч). Затем он готовит признаки, запускает модель, проверяет результат (validate_forecast с откатом на кривую мощности) и пишет объяснение. В LIVE инструменты выбирает LLM, в DEMO — детерминированный планировщик. Автономный прогон по февралю пересчитывает прогноз, когда выходит свежий выпуск погоды.
Ключевые решения
- HistGradientBoostingRegressor quantile
- конформная калибровка p10/p50/p90
- Open-Meteo Previous Runs (7 NWP)
- защита от утечки погоды
- паспорт выпуска с хешами
- бэктест 28 выпусков
- эмпирическая кривая мощности
Метрики
Метрики nMAE (% номинала) и сравнение с базовыми методами B0/B1 есть в разделе 8 README, но сами числа в карточку не попали
Особенности
Проверяемость прогноза: берётся только погода, опубликованная до момента решения, у каждого выпуска есть паспорт с хешами и неизменяемые версии. Команда документирует и неудачные эксперименты (признаки не улучшили MAE в 3 из 4 месяцев). Прогноз привязан к нормативам РК по заявкам ВИЭ. Интерфейс на трёх языках, есть роли и масштабирование на парк станций.
Стек
Python · FastAPI · scikit-learn · pandas · NumPy · HTTPX · React · TypeScript · Vite · ECharts · Leaflet · SQLite · Docker Compose · pytest
Модели
gpt-5.4-mini · OpenAI-совместимый API
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-be10e779-ku-group.
README
README.mdАнемо
Развёрнутая версия: https://hack.aican.cloud — живой режим с LLM; подробности в разделе 11. Проверка по этому README от неё не зависит: запуск из репозитория работает без ключа.
1. Название проекта
Анемо — агентная система прогнозирования почасовой выработки ветроэлектростанции на 24–48 часов.
Трек HackAlem AI — «Энергетика», задача — Agentic AI для прогнозирования выработки ВЭС. Формулировка задачи, исходные условия и допущения команды сохранены в CASE.md.
2. Краткое описание
Проект помогает диспетчеру или аналитику ВЭС оценить выработку станции на следующие двое суток, увидеть часы низкой генерации и неопределённость прогноза, а также сравнить новый выпуск с предыдущим.
На вход подаётся дата исторического выпуска. Агент сам запрашивает по координатам станции прогнозы погоды семи моделей Open-Meteo, выпущенные до момента решения (без сети — берёт архив из репозитория), рассчитывает 48 почасовых значений и показывает график, таблицу, пояснение и журнал своих действий в реальном времени.
Загружать ничего не нужно. История двух турбин от организатора и архив погоды уже лежат в репозитории; модель обучается на них сама при старте контейнера.
Текущая версия решает ретроспективную задачу февраля 2026 года: даты выпуска — с 31 января по 27 февраля, момент решения — 23:59 местного времени станции (UTC+5). Мощность дана в долях номинала от 0 до 1; установленная мощность в МВт организатором не предоставлена.
Практическая ценность для Казахстана
- Производитель ВИЭ подаёт заявку с почасовыми объёмами поставки до 08:00 по времени Астаны в сутки, предшествующие операционным суткам: пункт 9 правил, утверждённых приказом Министра энергетики РК от 2 марта 2015 года № 164. Выпуск делается в конце дня D, поэтому заявку на операционные сутки D+2 (срок — 08:00 дня D+1) можно подать уже по нему, а D+1 — самый свежий прогноз на ближайшие сутки для внутрисуточного планирования и оценки дисбаланса (
backend/app/forecast/pipeline.py). - Дисбаланс определяется как разница планового и фактического сальдо за каждый час операционных суток: пункт 78 Правил функционирования балансирующего рынка электрической энергии. Поэтому продукт показывает именно почасовой прогноз и выделяет часы существенного пересмотра (
backend/app/forecast/passport.py,frontend/src/features/forecast/). - По данным годового отчёта KEGOC за 2024 год, в Казахстане действовали 57 ВЭС суммарной мощностью 1 525,7 МВт. Задача точного планирования относится уже к значимому для энергосистемы классу генерации.
- Прогноз выработки ВИЭ развивают и крупные игроки (KEGOC, «Самрук-Энерго»), поэтому мы не заявляем первенство. Отличие решения — проверяемость: только погода, опубликованная до момента решения, паспорт и хеши каждого выпуска, измеренная польза против простых методов на одинаковых исторических условиях.
3. Что реализовано
| Требование или возможность | Состояние | Где реализовано | Как проверить |
|---|---|---|---|
| R1. Обучение модели на истории двух турбин | Реализовано; обучение при старте процесса | data.py, model.py | Дождаться model: ready в /health; расчёт метрик — раздел 8 |
| R2. Получение архивных прогнозов погоды по координатам | Реализовано; доступность в прошлом проверяется по правилу с задержкой 7 ч | weather.py, model.run_lead | Команда weather, тест временного правила, поле time_integrity |
| R3. Почасовой прогноз на 24–48 часов | Реализован горизонт 48 ч: станция и две турбины | pipeline.py | Выпуск 09.02 → 48 часов за 10–11.02 |
| R4. Агентный цикл и повторный расчёт | Семь инструментов, LIVE и планировщик без LLM; автономный прогон по дням: агент сам находит часы, для которых вышел более свежий выпуск погоды, и пересчитывает прогноз | agent.py (run, autonomous_run) | Пересчитать выпуск и смотреть живой журнал; «Прогноз на период» → автономный прогон |
| R5. Последовательные выпуски за тестовый период | Реализован прогон 28 дат | cli.py | 1 344 строки полного CSV и 672 строки итогового февраля |
| Диапазон неопределённости и проверка результата | Квантили p10/p50/p90, калибровка, проверка границ и порядка | calibrate.py, agent.validate | График, поле validation, тесты ядра |
| Паспорт и сохранённые версии выпуска | Реализованы хеши входов/результата, режим исполнения и сравнение выпусков | passport.py | passport в ответе API и JSON в outputs/forecasts |
| Интерфейс, графики и выгрузки | Вкладки «Прогноз», «Прогноз на период», «Качество модели», «Станции», «О проекте»; русский, казахский, английский | frontend/src/features | Ручной сценарий в разделе 8 |
| Живой журнал агента | Ходы LLM и вызовы инструментов появляются по мере выполнения, этапы отмечаются по ходу | agent.py (progress), GET /api/forecast/progress/{date}, AgentLog.tsx | Нажать «Пересчитать» и смотреть журнал |
| Вход и роли | Диспетчер — прогноз; аналитик — ещё полный прогон и автономный прогон; администратор — ещё станции. Чтение открыто | auth.py, stations.py, LoginBox.tsx | Кнопка «Демонстратор» в шапке; тест test_auth_stations.py |
| Станции и турбины (задел на масштабирование) | Раздел для масштабирования на парк станций владельца. Добавить станцию и турбины, загрузить историю CSV по месяцам (месяцы дописываются, повторы по времени заменяются; проверка столбцов, шага и диапазона мощности). Модель новой станции пересчитывается автоматически после каждой загрузки — эмпирическая кривая мощности p10/p50/p90 по всей истории; прогноз на 48 ч — по текущему ветру Open-Meteo для координат станции. Это упрощённая модель: бустинг, архивная погода и калибровка — только для станции из ТЗ | stations.py, station_model.py, stations | Вкладка «Станции» под «Демонстратором»; тест test_station_model.py |
Наличие реализации в таблице не означает, что все её режимы проверены на каждой машине. Сохранённые метрики и команды воспроизведения приведены в разделе 8; ограничения — в разделе 10.
4. Как работает решение
- Пользователь нажимает «Демонстратор» в шапке (вход одной кнопкой, учётка
demo/demoсо всеми правами), открывает вкладку «Прогноз», выбирает дату выпуска 09.02.2026 и объект «Станция». - Нажимает «Сделать прогноз» или «Пересчитать». При открытии даты интерфейс также может показать уже сохранённый выпуск.
- Агент оценивает погодные источники, получает прогнозы погоды, готовит признаки, запускает модель и проверяет результат. Каждый ход LLM и каждый вызов инструмента появляется в журнале в момент выполнения; строка внизу показывает, что происходит сейчас.
- На экране появляются 48 почасовых прогнозов на 10–11 февраля: медиана
p50, диапазонp10–p90, прогнозы турбин, ветер, пояснение и карточки внимания. - Пользователь смотрит таблицу по часам, сравнение с предыдущим выпуском, карточки внимания и журнал инструментов.
- На вкладке «Прогноз на период» доступны календарь 28 выпусков, итоговый график и два CSV, а также автономный прогон: агент проходит февраль по дням, на каждом дне проверяет, вышел ли более свежий выпуск погоды для уже спрогнозированных часов, и пересчитывает прогноз с записью пересмотра.
- На вкладке «Качество модели» показаны сохранённые метрики и сравнение прогноза с фактом января 2026 года.
Показатель дневной выработки — сумма нормированных почасовых значений, то есть эквивалентные часы работы на полной мощности, а не МВт·ч.
5. Технологии
| Компонент | Технологии и назначение |
|---|---|
| Сервер и API | Python 3.12, FastAPI, Uvicorn, Pydantic и pydantic-settings |
| Численная модель | pandas, NumPy, scikit-learn; HistGradientBoostingRegressor с квантильной функцией потерь |
| AI-агент | Собственный цикл вызова инструментов; OpenAI Python SDK и OpenAI-совместимый API в LIVE |
| Модель LLM по умолчанию | gpt-5.4-mini из конфигурации; меняется через LLM_MODEL |
| Погода | HTTPX и Open-Meteo Previous Runs API |
| Интерфейс | React, TypeScript, Vite, Apache ECharts, Lucide, Leaflet |
| Хранение | CSV и JSON для данных/результатов; SQLite и SQLAlchemy в инфраструктурном каркасе |
| Запуск и проверки | Docker Compose, pytest, Ruff, oxlint |
Зависимости Python зафиксированы в requirements.txt и requirements-dev.txt, frontend — в package-lock.json. SQLite не хранит прогнозы: они сохраняются в outputs/.
Роль AI и режимы
- DEMO, без LLM (в интерфейсе — «Режим проверки (без ключа)»): детерминированный планировщик выполняет те же инструменты и реальные численные расчёты. Для основного прогноза не нужны ключ и сохранённые ответы LLM.
- LIVE: при
APP_MODE=liveи заданномLLM_API_KEYмодель выбирает вызовы инструментов и формирует объяснение по их результатам. При недоступности LLM расчёт выполняет планировщик сmode: demo. При незавершённом LIVE-цикле дополнительно выставляетсяfallbackи добавляется запись в журнал. - Полный февральский прогон всегда выполняется планировщиком. Отдельные LIVE-выпуски хранятся как другой режим версии и не подменяют календарь этого прогона.
LLM не вычисляет мощность: прогноз, метрики, интервалы и сравнения рассчитывает Python-код. Общий LLM-клиент умеет сохранять ответы в data/ai-cache/; это отдельный механизм, а не основа DEMO-прогноза ВЭС.
Раскрытие сохранённых ответов LLM. В data/ai-cache лежат 12 JSON-файлов — ответы gpt-4o-mini-2024-07-18, записанные клиентом во время LIVE-прогонов при разработке 23.09.2026 (в каждом файле — модель, дата и хеш входа). Прогноз в режиме без ключа их не использует: планировщик не обращается к LLM. Проверка: удалить каталог и выполнить smoke — результат тот же.
При разработке использовались Claude Code (Максим и Оксана) и OpenAI Codex (Владимир). Вызовы LLM в продукте и использование ассистентов при разработке — разные роли.
6. Архитектура проекта
Браузер: React → HTTP API FastAPI
│
▼
агент / планировщик
1. rank_weather_sources
2. fetch_weather
3. build_features
4. run_forecast
5. validate_forecast
6. analyze_forecast
7. compare_with_previous
│
┌──────────┴──────────┐
▼ ▼
прогноз и журнал паспорт и версия
→ график/таблица → outputs/forecasts/
- main.py подключает API, запускает обучение модели в фоне и отдаёт собранный frontend.
- api/forecast.py принимает запросы прогноза, истории, метрик и полного прогона.
- forecast/data.py агрегирует историю турбин; weather.py читает или скачивает погодные архивы.
- model.py обучает квантильные модели станции и медианные модели турбин; calibrate.py корректирует ширину интервала.
- agent.py управляет инструментами; passport.py сохраняет происхождение входов и версии.
- Dockerfile собирает frontend и backend в один контейнер с одним портом.
Паспорт содержит момент решения, период прогноза, границу обучения, погодные источники, идентификаторы модели и калибровки, input_hash, result_hash и режим исполнения. Режим исполнения входит в хеш входов, поэтому LIVE и DEMO получают разные версии даже при одинаковых численных входах. Существующий файл версии не перезаписывается. Сравнение использует сохранённый предыдущий выпуск; если его нет, применяется явно отмеченная реконструкция.
7. Установка и запуск
Основной способ: Docker
Нужны Git, Docker Engine или Docker Desktop с работающим движком и Docker Compose v2, поддерживающий параметр env_file.required из docker-compose.yml. Порт 8000 должен быть свободен.
Для первой сборки нужен интернет: скачиваются образы и зависимости. После сборки основной DEMO-сценарий использует данные из репозитория и работает без ключа и интернета. Подложка карты загружается из сети отдельно.
Команды выполняются из терминала Bash либо PowerShell:
git clone https://github.com/BAITC-Hacks/hack-be10e779-ku-group.git
cd hack-be10e779-ku-group
docker compose config --quiet
docker compose up --build
Если репозиторий закрыт, для клонирования нужен предоставленный организатором доступ к нему. Личный аккаунт участника или его API-ключ для DEMO-прогноза не требуется.
Файл .env для первого запуска не обязателен. Если нужна настройка порта или LIVE-режима, перед запуском создайте его из .env.example, только если своего файла ещё нет:
# Bash, из корня репозитория
test -f .env || cp .env.example .env
# PowerShell, из корня репозитория
if (-not (Test-Path .env)) { Copy-Item .env.example .env }
Откройте http://localhost:8000 и нажмите «Демонстратор» в шапке. Чтение (графики, метрики, сохранённые выпуски) открыто без входа; запуск прогноза и прогонов требует роли, форма входа откроется сама. Тестовые учётки — только для проверки, заданы в .env.example и config.py:
| Логин / пароль | Роль | Что разрешено |
|---|---|---|
demo / demo | администратор | всё — кнопка «Демонстратор» |
dispatcher / dispatcher123 | диспетчер | прогноз |
analyst / analyst123 | аналитик | + полный прогон февраля и автономный прогон |
admin / admin123 | администратор | + станции, турбины, загрузка истории |
Во втором терминале проверьте http://localhost:8000/health: для готовности прогноза нужны status: "ok" и model: "ready". Пока идёт обучение, состояние — warming; один status: "ok" не доказывает готовность модели.
Если model: "error", посмотрите docker compose logs app и наличие обоих файлов в data/raw/. Ошибка при разборе env_file.required означает, что Compose нужно обновить. Если занят порт, задайте в .env APP_PORT=8080 и открывайте порт 8080.
Остановить приложение можно через Ctrl+C, затем docker compose down. В Compose не настроен постоянный том: новые результаты внутри контейнера нужно скачать или скопировать до его удаления.
Параметры окружения
| Имя | Назначение | По умолчанию | Когда нужно менять |
|---|---|---|---|
APP_MODE | demo — планировщик, live — LLM | demo | Для LIVE |
LLM_API_KEY | Ключ провайдера LLM | Пусто | Только для LIVE |
LLM_MODEL | Модель LLM | gpt-5.4-mini | При выборе другой модели |
LLM_BASE_URL | OpenAI-совместимый адрес; пусто — OpenAI | Пусто | Для другого провайдера |
APP_PORT | Внешний порт Docker | 8000 | Если порт занят |
BUILD_COMMIT | Метка сборки в /health | dev | Для идентификации развёрнутой версии |
LLM_TIMEOUT_S | Таймаут запроса LLM, секунд | 60 | При необходимости |
DATABASE_URL | SQLite инфраструктурного каркаса | sqlite:///<корень>/data/app.db | Для другого хранилища каркаса |
AI_CACHE_DIR | Каталог сохранённых ответов LLM | <корень>/data/ai-cache | Для другого каталога |
STATIC_DIR | Каталог собранного frontend | <корень>/frontend/dist | При другом размещении |
WEATHER_ONLINE | 1 — агент сам запрашивает Open-Meteo на окно выпуска, без сети откатывается на data/weather/; 0 — только архив | 1 | Для полностью офлайн-проверки |
AUTH_REQUIRED | 1 — действия требуют входа; 0 — проверка ролей отключена | 1 | Отключать только локально |
AUTH_SECRET | Секрет подписи токенов | change-me-in-production | Обязательно на своём сервере |
AUTH_USERS | Учётки логин:пароль:роль через запятую | четыре тестовые учётки | На своём сервере |
Источник значений — config.py и docker-compose.yml. BUILD_COMMIT, LLM_TIMEOUT_S, DATABASE_URL, AI_CACHE_DIR и STATIC_DIR отсутствуют в шаблоне .env.example, но поддерживаются кодом или сборкой. Без ключа приложение остаётся в DEMO. Ключи нельзя коммитить.
Запуск для разработки без Docker
Нужны Python 3.12, Node.js 20.19+ в ветке 20 либо Node.js 22.12+ и npm. В контейнере используется Node.js 24. Далее команды для Bash, из корня репозитория:
python3.12 -m venv backend/.venv
backend/.venv/bin/python -m pip install -r backend/requirements-dev.txt
cd backend
.venv/bin/python -m uvicorn app.main:app --reload --port 8000
Во втором терминале, из корня репозитория:
cd frontend
npm ci
npm run dev
Откройте http://localhost:5173: Vite проксирует /api и /health на backend. В PowerShell используйте python версии 3.12 и пути backend/.venv/Scripts/python.exe / .venv/Scripts/python.exe вместо путей bin/python.
8. Как проверить решение
Повторяемый сценарий для жюри
После готовности модели:
| Шаг | Действие | Ожидаемый результат |
|---|---|---|
| 0 | Нажать «Демонстратор» в шапке | В шапке «демонстратор · администратор» |
| 1 | «Прогноз» → дата 09.02.2026 → «Станция» → «Пересчитать» / «Сделать прогноз» | 48 часов: с 10.02 00:00 по 11.02 23:00, UTC+5 |
| 2 | Во время расчёта смотреть журнал агента, затем открыть почасовую таблицу | Шаги появляются по ходу, этапы отмечаются по одному; значения в пределах 0–100%, прогноз внутри показанного диапазона; видны семь инструментов |
| 3 | Переключиться на турбину 1 или 2 | График показывает выбранную турбину |
| 4 | Изменить дату на 10.02 и пересчитать | Новый выпуск на 11–12.02; сравнение с предыдущим выпуском |
| 5 | «Прогноз на период» → скачать оба CSV | Все выпуски: 1 344 строки; итог: 672 часа 01–28.02 |
| 5а | «Прогноз на период» → запустить автономный прогон | Лента по дням: решение агента, свежесть погоды, пересмотр; около 3 с на день |
| 6 | «Качество модели» → дата январского выпуска 20.01 | График прогноза и фактической выработки за 21–22.01; модель может быть хуже базового метода на отдельном выпуске |
| 7 | «Станции» → добавить станцию и турбину → загрузить файл data/raw/turbine1.csv из репозитория (перетащить или «Загрузить файлы») → шаг 3, прогноз | Отчёт проверки файла и покрытие по месяцам; «модель пересчитана: кривая мощности по 23 763 ч истории»; прогноз на 48 ч по текущему ветру Open-Meteo (нужна сеть). Это упрощённая модель для масштабирования, не модель из ТЗ |
Сохранённые файлы — результаты вычислений, а не факт февраля и не доказательство нового расчёта. Для проверки вычисления используйте кнопку пересчёта или POST, а не только открытие сохранённого выпуска.
Автоматический smoke и API
В Bash (Linux/macOS, Git Bash или WSL), при запущенном приложении, из корня:
bash scripts/smoke.sh
Скрипт ждёт готовности модели до 300 секунд, проверяет, что без входа прогноз отклоняется (401), входит тестовым диспетчером (SMOKE_USER / SMOKE_PASS), рассчитывает прогноз на 09.02, проверяет 48 часов, временное правило, наличие основных шагов агента, ошибку для даты вне диапазона, метрики, историю и главную страницу. Успешный итог — Smoke пройден. Для другого порта: bash scripts/smoke.sh http://localhost:8080.
Прямой запрос в Bash: сначала вход, затем прогноз с токеном.
TOKEN=$(curl -s http://localhost:8000/api/auth/login -H 'Content-Type: application/json' \
-d '{"username":"demo","password":"demo"}' | sed -E 's/.*"token":"([^"]+)".*/\1/')
curl --fail --max-time 300 http://localhost:8000/api/forecast \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"issue_date":"2026-02-09"}'
В PowerShell:
$login = Invoke-RestMethod -Method Post -Uri http://localhost:8000/api/auth/login -ContentType 'application/json' -Body '{"username":"demo","password":"demo"}'
$headers = @{ Authorization = "Bearer $($login.token)" }
$result = Invoke-RestMethod -Method Post -Uri http://localhost:8000/api/forecast -Headers $headers -ContentType 'application/json' -Body '{"issue_date":"2026-02-09"}'
$result.hours.Count
$result.time_integrity.ok
$result.validation.ok
Ожидается 48, True, True. Ответ также содержит steps, mode, passport, cards и weather_retrieval (откуда агент взял погоду: сеть или архив, снимок с хешем, семь источников). Без токена прогноз возвращает HTTP 401. Выпуск 2026-03-15 должен вернуть HTTP 400; отсутствие обязательной даты — HTTP 422. Полный API доступен в Swagger, маршруты — в api/forecast.py.
Пересчёт февраля и метрик
Из корня репозитория при работающем контейнере:
docker compose exec app python -m app.forecast.cli backtest
docker compose cp app:/app/outputs/forecast_feb2026.csv ./forecast_feb2026.csv
docker compose cp app:/app/outputs/forecast_feb2026_final.csv ./forecast_feb2026_final.csv
docker compose exec app python -m app.forecast.cli metrics
При локальном запуске те же команды python -m app.forecast.cli backtest и python -m app.forecast.cli metrics выполняются из backend/ в установленном окружении.
Полный CSV содержит 28 × 48 = 1 344 строки, включая D+2 последнего выпуска — 1 марта, помеченное outside_test_period. Итоговый CSV содержит только D+1 каждого выпуска — 672 часа февраля. Повторный прогон пересоздаёт CSV; версии JSON сохраняются отдельно.
Сохранённые показатели качества
Источник — outputs/metrics.json. Проверка: скользящие месяцы октябрь 2025 — январь 2026, обучение до каждого проверяемого периода с временным отступом для D+2. Методика реализована в model.holdout_metrics; команда metrics воспроизводит расчёт. GET /api/metrics возвращает метрики и поле calibration из outputs/calibration.json.
Мощность нормирована к номиналу: значения MAE и RMSE ниже умножены на 100 и выражены в процентах номинальной мощности.
| Горизонт | Метод | Часов | nMAE, % | nRMSE, % |
|---|---|---|---|---|
| D+1 | Бустинг, ансамбль погоды | 2 885 | 14,90 | 22,25 |
| D+1 | Кривая мощности | 2 885 | 18,17 | 26,95 |
| D+1 | Персистентность («завтра как сегодня») | 2 846 | 35,55 | 47,50 |
| D+2 | Бустинг, ансамбль погоды | 2 885 | 16,09 | 23,75 |
| D+2 | Кривая мощности | 2 885 | 19,30 | 28,34 |
| D+2 | Персистентность («завтра как сегодня») | 2 826 | 37,34 | 48,95 |
Для персистентности доступно меньше часов, поэтому сравнение с ней выполнено не на строго одинаковом наборе наблюдений. Проверка исключения gfs_ws100 не улучшила MAE (D+1: 0,1495 против 0,1490); агент исключает источники при пропусках в прогнозном окне.
По outputs/calibration.json, калибровка на октябре–декабре увеличила покрытие p10–p90 на отложенном январе с 66,5% до 77,5% при цели 80%; средняя ширина интервала выросла с 0,445 до 0,477. Это измерение на прошлом периоде, а не гарантия покрытия будущих наблюдений.
Для контекста, обзор Giebel et al. со ссылкой на опыт Германии (Rohrig) приводит для day-ahead прогноза отдельной ВЭС диапазон 10–20% RMSE от номинальной мощности (стр. 59 отчёта). Наши 22,25% для D+1 и 23,75% для D+2 находятся выше этого ориентира; сравнение ориентировочное, поскольку площадки, периоды и доступные входы различаются.
Что проверили и не взяли. Дополнительные эксперименты с признаками, смесью модели и кривой мощности, средним прогнозом турбин и старыми погодными выпусками не вошли в рабочую модель.
| Гипотеза (оценка: окт 2025 — янв 2026, критерий — выигрыш ≥ 0,002 в 3 из 4 месяцев) | Среднее MAE, база 0,1546 | Решение |
|---|---|---|
| Ансамбль 6 моделей погоды (ECMWF, ICON, GFS, JMA, CMA, GEM: значения, среднее, разброс) | −11 % к одному best_match | принято |
Исключение худшего источника (gfs_ws100) по ошибке ветра (B0/B1) | 0,1495 против 0,1490 (D+1) | не брать |
Плотность воздуха, ρ·v³, ветер 80/120 м, вес свежих данных | без устойчивого выигрыша | не брать |
| Смесь модели с кривой мощности (вес по прошлому месяцу) | 0,1548 | не брать |
| Прогноз станции как среднее турбинных моделей | 0,1542 (2 из 4) | не брать |
| Медленный бустинг (500 деревьев, шаг 0,04) | 0,1526 (2 из 4), обучение ×2,5 | не брать |
| Lagged ensemble — выпуски за N+1, N+2 суток того же часа | 0,1545 (1 из 4) | не брать |
| Траектория прогнозного ветра ±3 ч того же выпуска | 0,1526 (2 из 4) | не брать |
| Соседние точки сетки ±0,25–0,5°: градиенты давления, «гора − станция», кольцо ветра | 0,1529–0,1564 | не брать |
Вывод: при доступных архивных прогнозах погоды модель близка к пределу; дальнейший выигрыш требует новой информации (например, оперативной телеметрии SCADA), которой в кейсе нет. Критерий принятия — среднее по D+1 и D+2 снижение MAE минимум на 0,002 хотя бы в трёх из четырёх месяцев проверки. Код находится в backend/experiments, результаты — в журнале backend.
Тесты и сборка
После установки зависимостей, в Bash из корня:
cd backend
.venv/bin/python -m pytest -q
.venv/bin/python -m ruff check .
Отдельно из frontend/:
npm run build
npm run lint
Тесты ядра проверяют горизонт, границы, порядок квантилей и правило доступности погоды. Тесты API включают как подменённые ответы для проверки контрактов, так и test_forecast_real_agent с настоящим расчётом без LLM. В тестах ключ отключён через conftest.py; их успешность не подтверждает доступность LIVE-провайдера.
9. Данные и интеграции
История турбин и погодные данные
- data/raw/turbine1.csv и turbine2.csv — предоставленная организатором история с 11.03.2023 по 31.01.2026: время, ветер, температура и нормированная активная мощность, шаг 10 минут. Это исходные данные кейса, не синтетический набор.
- Часовая точка — среднее шести 10-минутных измерений; неполные часы исключаются. Мощность станции — среднее нормированных мощностей обеих турбин при наличии обеих.
- Координаты Т1: 43.645150, 78.535604; Т2: 43.643198, 78.538828. Для погодного запроса используется общая точка станции: 43.6442, 78.5372.
- data/weather содержит ответы Open-Meteo Previous Runs API:
best_match, ECMWF IFS, ICON, GFS, JMA, CMA и GEM. Данные распространяются по CC BY 4.0; источник — Open-Meteo, лицензия. - Свои данные. Модель читает ровно два файла
data/raw/turbine1.csvиturbine2.csvв формате организатора. Чтобы проверить на других данных тех же столбцов, замените файлы и перезапустите контейнер: модель переобучится при старте. На данных, отличных от кейса, это не проверялось. Загрузка CSV во вкладке «Станции» (демо масштабирования) строит для новой станции упрощённую модель — кривую мощности по её истории — и прогноз по текущему ветру Open-Meteo; полная модель с агентным циклом и архивной погодой — только для станции из ТЗ. - outputs содержит вычисленные прогнозы, метрики и калибровку. Они не являются измеренной выработкой февраля. Синтетические ответы встречаются в тестовых фикстурах и не используются как исходная история для модели.
Погодный архив можно обновить командой docker compose exec app python -m app.forecast.cli weather; для неё нужен интернет. В штатной проверке обновление не требуется. После обновления перезапустите приложение для повторного обучения и выполните пересчёт.
Проверка доступности погоды в прошлом
Для целевого часа h выбирается минимальное N из 1, 2, 3, удовлетворяющее правилу:
h − N суток + 7 часов ≤ момент решения D, 23:59 UTC+5
Для выпуска 09.02 это 17 часов с previous_day1, 24 — с previous_day2 и 7 — с previous_day3. В прогнозных признаках используются архивные прогнозы, а не фактическая погода будущих часов.
Задержка 7 часов — допущение реализации. Статус verified_by_rule подтверждает выполнение этого правила; код не получает индивидуальные подтверждённые отметки публикации каждого NWP-выпуска.
Внешние сервисы
Open-Meteo получает координаты, период и перечень погодных переменных. В LIVE внешнему LLM API передаются инструкция, запрос и результаты вызванных инструментов. При просмотре карты браузер обращается к тайлам OpenStreetMap. Для DEMO-прогноза внешние аккаунты не нужны; LIVE требует настроенного ключа провайдера. Адрес другого OpenAI-совместимого сервиса задаётся через LLM_BASE_URL, но совместимость каждого такого сервиса отдельно не гарантируется.
Раскрытие заготовок и сторонних материалов
До старта были подготовлены организационные инструкции AGENTS.md, CLAUDE.md, предварительные документы в docs/, команды и настройки Claude Code, preflight.sh, общий каркас FastAPI/React/Vite, конфигурация SQLite, LLM-клиент и общий цикл инструментов, загрузка файлов, Docker Compose, базовый smoke и шаблон README. Эти заготовки не содержали предметного решения задачи ВЭС. Также заранее была подготовлена серверная инфраструктура, описанная в docs/deploy.md.
До старта команда провела с AI-ассистентами обзор отраслей и треков; обзор не включён в репозиторий. Предметная реализация отражена в истории коммитов и docs/progress.md.
| Компонент | Назначение | Лицензия / условия | Источник |
|---|---|---|---|
| Данные двух турбин | Обучение и проверка | Предоставлены организатором для кейса; отдельная открытая лицензия не указана | CASE.md, data/raw |
| Open-Meteo и перечисленные NWP-источники | Архивные погодные прогнозы | CC BY 4.0 | Open-Meteo |
| FastAPI, Pydantic, pydantic-settings | API, валидация, настройки | MIT | FastAPI, Pydantic, pydantic-settings |
| Starlette | Основа HTTP-приложения FastAPI | BSD-3-Clause | Лицензия Starlette |
| Uvicorn | Сервер ASGI | BSD-3-Clause | Uvicorn |
| SQLAlchemy | Инфраструктура SQLite | MIT | SQLAlchemy |
| python-multipart | Инфраструктура загрузки файлов | Apache-2.0 | python-multipart |
| pandas, NumPy, scikit-learn | Ряды и прогнозная модель | BSD-3-Clause | pandas, NumPy, scikit-learn |
| HTTPX | HTTP-клиент | BSD-3-Clause | HTTPX |
| OpenAI Python SDK | Вызовы LIVE-агента | Apache-2.0 | openai-python |
| Модель LLM провайдера | Выбор инструментов и объяснение | Условия выбранного API; веса в репозитории не распространяются | Конфигурация, клиент |
| React, React DOM | Интерфейс | MIT | React |
| Apache ECharts | Графики | Apache-2.0 | ECharts |
| Leaflet | Карта станции | BSD-2-Clause | Leaflet |
| OpenStreetMap | Подложка карты | ODbL | OpenStreetMap |
| Логотипы HackAlem AI, организаторов и партнёров | Указание события и его организаторов в подвале интерфейса | Отдельная открытая лицензия в репозитории не указана | hackalem.ai, файлы, источник и назначение в коде |
| Lucide | Иконки | ISC | Lucide |
| Manrope, JetBrains Mono через Fontsource | Локальные шрифты | OFL-1.1 | Manrope, JetBrains Mono |
| Vite, create-vite, plugin-react | Сборка и шаблон frontend | MIT | Vite |
| TypeScript | Типизация | Apache-2.0 | TypeScript |
| pytest, Ruff, oxlint | Тесты и линтеры | MIT | pytest, Ruff, oxc |
10. Ограничения
- Это ретроспективная система для двух заданных турбин. Произвольные даты вне 31.01–27.02.2026 не принимаются; постоянного мониторинга новых погодных выпусков нет.
- Факта февраля 2026 года нет, поэтому точность на тестовом месяце локально не оценена. Метрики прошлых месяцев не гарантируют такой же результат в феврале.
- Номинальная мощность неизвестна: вывод в МВт и МВт·ч не реализован. Среднее нормированных мощностей двух турбин — принятое в кейсе допущение.
- У турбины 1 есть крупные пропуски истории в мае–июле 2024 года. Неполные часы отбрасываются; источники сравниваются с учётом доступных наблюдений.
- Проверка доступности погоды основана на описанном правиле с задержкой 7 часов, а не на журнале реальных публикаций провайдера.
- Целевое покрытие диапазона 80% не достигнуто: на январской проверке после калибровки — 77,5%.
- LIVE зависит от внешнего API и ключа. Без него сохраняется численный прогноз планировщика, но нет живого выбора инструментов моделью.
- Учётки в
.env.example— тестовые, для проверки. На своём сервере нужно задатьAUTH_SECRETиAUTH_USERS. Пользователи хранятся в переменной окружения, регистрации нет. - Карта требует сети. Отсутствие тайлов не мешает численному прогнозу.
- Для добавленных станций используется упрощённая модель — эмпирическая кривая мощности по загруженной истории и текущий прогноз ветра Open-Meteo (нужна сеть). Бустинг, ансамбль архивной погоды и калибровка интервала для них не обучаются; интервал p10–p90 — разброс мощности в бине ветра из истории.
- Пороги карточек пересмотра на 10 процентных пунктов и ширины диапазона 30 процентных пунктов заданы командой для демонстрации; это не нормативы диспетчерского управления.
- Результаты записываются в локальные файлы; постоянный том Docker и многопользовательская эксплуатация не настроены. Торговля электроэнергией и управление оборудованием не реализованы.
11. Ссылка на развёрнутую версию
https://hack.aican.cloud — развёрнута конкурсная версия; работает в живом режиме (LIVE):
шаги агента выбирает LLM (gpt-5.4-mini, ключ команды), числа считает тот же код, что в репозитории.
Какой коммит развёрнут, видно в GET https://hack.aican.cloud/health (поле commit); как развёрнуто — docs/deploy.md,
раздел «Развёрнуто 23.09».
Проверено 23.09.2026: /health → mode: live, model: ready; главная страница, /api/meta, /api/backtest, /api/metrics,
/api/holdout и сохранённый выпуск GET /api/forecast/2026-02-09 отвечают 200.
LIVE-прогноз POST /api/forecast на 2026-02-09 по публичному адресу — HTTP 200 за 16 с: LLM сама прошла все семь инструментов
(fallback: false), 48 часов, проверка времени пройдена, выпуск сохранён отдельной версией с execution_mode: llm.
Ссылка — дополнение, а не замена: запуск из репозитория (раздел 7) от неё не зависит и работает без ключа в режиме DEMO.
Сервер общий, поэтому после перезапуска контейнера модель прогревается ~20–25 минут: интерфейс открывается сразу,
а новый прогноз ждёт окончания прогрева (model: ready в /health).
Авторы коммитов
История коммитов
- 2026-09-23 17:44chore: .gitattributes — *.sh всегда с LF, иначе smoke.sh падает на клоне с CRLF (Windows/WSL)Оксана
- 2026-09-23 17:37docs: шаг «Станции» в сценарии жюри на файле турбины из репозитория; актуальный статус при загрузке истории одним файломMaximushkaBed
- 2026-09-23 17:32docs: вкладка «Станции» — демо масштабирования (значок, пояснение, «О проекте»), README без противоречия про прогноз новых станцийОксана
- 2026-09-23 17:25feat: понятная вкладка «Станции» по шагам — турбины → загрузка истории (перетаскивание, отчёт проверки файлов, покрытие по месяцам) → модель и прогноз; линтер в экспериментеОксана
- 2026-09-23 17:10docs: ссылка на развёрнутую версию в начале READMEMaximushkaBed
- 2026-09-23 17:09docs: README и stations.py — новая станция получает упрощённую модель автоматически (убрано устаревшее «не обучается»)Оксана
- 2026-09-23 17:09feat: новые станции — загрузка истории турбин по месяцам, автоматический пересчёт кривой мощности, прогноз на 48 ч; вкладка «Станции»; README и тест; понятный текст при входеОксана
- 2026-09-23 17:08docs: README — вход и тестовые учётки, запросы API с токеном, переменные авторизации и погоды, живой журнал, автономный прогон, раскрытие сохранённых ответов LLM; раздел 11 — развёрнутая версияMaximushkaBed
Все коммиты (63)
- 2026-09-23 17:03feat: живой журнал агента — ходы LLM и инструменты появляются по мере выполнения, строка «что происходит сейчас» вместо крутилкиMaximushkaBed
- 2026-09-23 16:58fix: этапы агента отмечаются по ходу работы, а не все сразу после ответа — прогресс шагов с бэкендаMaximushkaBed
- 2026-09-23 16:48fix: validation и калибровка в ответах API по ревью; кнопка «Демонстратор» (demo/demo, все права); .env.example честно описывает режим без ключаMaximushkaBed
- 2026-09-23 16:34merge: main в i18n — вход в шапке на трёх языкахОксана
- 2026-09-23 16:33merge: main в i18n — перевод новых экранов (прогноз на период, автономный прогон, получение погоды), режим проверки на трёх языкахОксана
- 2026-09-23 16:30feat: вход в шапке интерфейса — токен в запросах, форма открывается сама на 401/403, тестовые учётки в подсказкеMaximushkaBed
- 2026-09-23 16:25feat: интерфейс на трёх языках (қазақша, русский, English) и тема «как в системе» без мигания при загрузкеОксана
- 2026-09-23 16:23refactor: вкладка «Прогноз на период» без дублей — главное, агент (5 последних дней), календарь и почасовой график, CSVОксана
- 2026-09-23 16:19feat: авторизация по ролям, станции и турбины с загрузкой истории; поле weather_retrieval в ответе прогнозаMaximushkaBed
- 2026-09-23 16:16feat: лента «Агент проходит февраль сам» (автономный прогон), бейдж получения погоды агентом, «Режим проверки (без ключа)» вместо DEMOОксана
- 2026-09-23 16:11feat: вкладка «Прогноз на период» вместо «Февраль 2026» — период из API, февраль как тестовый период ТЗОксана
- 2026-09-23 16:08feat: агент сам получает погоду по координатам (7 источников, снимок с хешем, откат на архив) и автономный прогон по дням с обнаружением обновления входных данных и пересчётомMaximushkaBed
- 2026-09-23 16:01feat: вкладка «О проекте» — презентация продукта; карта «откуда погода» с номерами узлов и обеими турбинами; «7 источников погоды»; без выгрузки журнала в JSONОксана
- 2026-09-23 15:53docs: README — вернуть ценность для Казахстана, сравнение с отраслевой нормой и таблицу 10 проверенных гипотезMaximushkaBed
- 2026-09-23 15:53exp: траектория ветра (Codex) и соседние точки сетки — не прошли критерий 3 из 4 месяцевMaximushkaBed
- 2026-09-23 15:49docs: привести README к инструкции хакатона и проверяемому сценариюVladimir
- 2026-09-23 15:49docs: синхронизировать название Анемо и раскрыть логотипыVladimir
- 2026-09-23 15:47docs: README сверен с кодом — роли горизонтов для заявки ВИЭ, раскрытие всех зависимостей, калибровка, паспорт; название «Анемо»MaximushkaBed
- 2026-09-23 15:47checkpoint(час 3): API под фронт, валидатор агента, честная оценка, smoke в Docker, READMEMaximushkaBed
- 2026-09-23 15:44exp: смесь с кривой мощности, среднее турбин, медленный бустинг, lagged ensemble — ни один не прошёл критерий 3 из 4 месяцевMaximushkaBed
- 2026-09-23 15:40feat: название «Анемо» и знак-ветротурбина — шапка, favicon, заголовок вкладки, «О системе», футерОксана
- 2026-09-23 15:35feat: футер — проект в рамках HackAlem AI, лента организаторов и партнёров хакатона (логотипы с hackalem.ai)Оксана
- 2026-09-23 15:28feat: понятные вкладки «Февраль» и «Качество» — главное одной фразой, язык без жаргона, подписи методовОксана
- 2026-09-23 15:27fix: LIVE-выпуск — отдельная версия со своим паспортом; в DEMO /health без имени LLMMaximushkaBed
- 2026-09-23 15:25fix: календарь = официальный прогон планировщика, holdout с хешем калибровки и автопересчётом; smoke в Docker пройденMaximushkaBed
- 2026-09-23 15:24docs: README — архитектура агента, честность по времени, паспорт и версии, метрики и проверка B0/B1, Казахстан, раскрытиеMaximushkaBed
- 2026-09-23 15:23docs: уточнить инструкцию по READMEVladimir
- 2026-09-23 15:23fix: фронт под новые правила агента — шаг проверки результата, порог неуверенности 0.60, источники исключаются только при пропускахОксана
- 2026-09-23 15:21feat: понятный первый экран — главный вывод, что сделать диспетчеру, как это работает, карта станции и откуда погода, язык без жаргонаОксана
- 2026-09-23 15:19feat: инструмент агента validate_forecast — проверка результата перед выдачей с откатом на кривую мощности; порог флага неопределённости по распределению февраляMaximushkaBed
- 2026-09-23 15:15fix: честная оценка — граница обучения S−1 сут−1 ч, точная конформная статистика; источник исключается только при пропусках (B0/B1 показал, что исключение по ошибке не помогает)MaximushkaBed
- 2026-09-23 15:09docs: журнал по часам (часы 1–2 по истории коммитов)MaximushkaBed
- 2026-09-23 15:07chore: метрики — nMAE в % номиналаMaximushkaBed
- 2026-09-23 15:05fix: время в time_integrity в ISO, флаг fallback, имя LLM в /health; бриф сверен с кодомMaximushkaBed
- 2026-09-23 15:03feat: эндпоинты под фронт — meta, сохранённый выпуск, бэктест из версий, CSV, holdout; паспорт и карточки в схемахMaximushkaBed
- 2026-09-23 14:52feat: паспорт прогноза и неизменяемые версии выпусков, сравнение с сохранённым прошлым выпуском, карточки для диспетчера; прогон февраля через агентаMaximushkaBed
- 2026-09-23 14:52feat: веб-интерфейс по контракту API — прогноз с журналом агента, февраль, качество модели, о системеОксана
- 2026-09-23 14:47exp: проверка признаков (плотность воздуха, ветер 80/120 м, вес свежих данных) — ни один не улучшил MAE в 3 из 4 месяцевMaximushkaBed
- 2026-09-23 14:46docs: бриф — поправки после реализации (дата выпуска, правило погоды, 6 инструментов, метрики, кэш)Оксана
- 2026-09-23 14:45fix: погода без утечки — для каждого часа самый свежий выпуск NWP, опубликованный до момента прогноза (задержка 7 ч, выпуски за 1–3 суток); пересчёт калибровки, метрик и февраляMaximushkaBed
- 2026-09-23 14:45feat: API на агенте, прогрев модели при старте, outputs в образе, smoke под сценарий прогнозаMaximushkaBed
- 2026-09-23 14:15docs: контракт API v2 по коду агента, момент прогноза — конец дня DОксана
- 2026-09-23 14:11feat: API прогноза — forecast, backtest, metrics, history по контрактуMaximushkaBed
- 2026-09-23 14:11docs: README по ТЗ и тесты ядра (нет утечки погоды, горизонты, диапазоны); игнор своп-файловMaximushkaBed
- 2026-09-23 14:08docs: удалить файл хакатона и добавить инструкцию READMEVladimir
- 2026-09-23 14:06docs: правило — коммиты без строк соавторства AIMaximushkaBed
- 2026-09-23 14:06feat: агент прогноза — 6 инструментов цикла ТЗ, проверка честности по времени, выбор источников погоды, конформная калибровка интервалаMaximushkaBed
- 2026-09-23 14:01docs: добавить документ по хакатонуVladimir
- 2026-09-23 13:56feat: ядро прогноза ВЭС — архивная погода 6 моделей, бустинг с квантилями, цикл ТЗ, бэктест февраля; память командыMaximushkaBed
- 2026-09-23 13:48docs: дизайн-бриф интерфейса и ответы организаторов в CASE.mdОксана
- 2026-09-23 13:42docs: контракт API для веба (прогноз, бэктест, метрики, история)MaximushkaBed
- 2026-09-23 13:41docs: план P0 и решения по кейсу ВЭСMaximushkaBed
- 2026-09-23 13:36docs: разбор кейса — CASE.md и исторические данные турбин от организаторовMaximushkaBed
- 2026-09-23 13:27chore: типовой каркас (FastAPI, React+Vite, Docker), подготовленный до стартаMaximushkaBed
- 2026-09-23 13:26chore: импорт раскрытых заготовок, подготовленных до стартаMaximushkaBed
Структура репозитория (262 файлов)
.claude/commands/api-contract.md .claude/commands/case-intake.md .claude/commands/freeze.md .claude/commands/hourly.md .claude/commands/judge.md .claude/commands/p0-plan.md .claude/commands/smoke.md .claude/settings.json .dockerignore .env.example .gitattributes .gitignore AGENTS.md CASE.md CLAUDE.md DECISIONS.md Dockerfile README.md TASKS.md backend/app/__init__.py backend/app/ai/__init__.py backend/app/ai/agent.py backend/app/ai/llm.py backend/app/api/__init__.py backend/app/api/forecast.py backend/app/api/station_model.py backend/app/api/stations.py backend/app/auth.py backend/app/config.py backend/app/db.py backend/app/forecast/__init__.py backend/app/forecast/agent.py backend/app/forecast/calibrate.py backend/app/forecast/cli.py backend/app/forecast/data.py backend/app/forecast/model.py backend/app/forecast/passport.py backend/app/forecast/pipeline.py backend/app/forecast/weather.py backend/app/main.py backend/app/models.py backend/app/schemas.py backend/app/services/__init__.py backend/app/services/uploads.py backend/experiments/curve_feature_exp.py backend/experiments/features_exp.py backend/experiments/lagged_exp.py backend/experiments/model_exp.py backend/experiments/nwp_weight_exp.py backend/experiments/spatial_exp.py backend/experiments/trajectory_exp.py backend/pyproject.toml backend/requirements-dev.txt backend/requirements.txt backend/tests/conftest.py backend/tests/test_ai.py backend/tests/test_api_forecast.py backend/tests/test_auth_stations.py backend/tests/test_forecast_core.py backend/tests/test_health.py backend/tests/test_llm_live.py backend/tests/test_routes.py backend/tests/test_station_model.py data/ai-cache/.gitkeep data/ai-cache/1ec42728c1f154bc944169851e5586e043655289086e97eb29be7d9e39189a98.json data/ai-cache/221cd3714d1063e4b9f329d73da6d9d013f789ec80b8b9bc11af0fa6636a008e.json data/ai-cache/23e090f2577ad5523c01e071df65963b4655b5eac5350baa71d46abfdafd0a3b.json data/ai-cache/4a7817a039f02b40a4cbf12912df663dc53c22784bb3203d365bbdd01aaee932.json data/ai-cache/6acfc42a076baeb76eab09477189594542f5921e809929fcf067f25163a37cd2.json data/ai-cache/943f92e9db624b8444504c9708ba172898239cffaa767ecb374f98ea4b2f3a05.json data/ai-cache/9be1190b15aa52708967d98fc44a3db2a9f28cbab39815b94c841ec3334a7933.json data/ai-cache/a236935991c394552b248abd085ddf09d8884d9e0f78364d0136d2d6966491c9.json data/ai-cache/a877b4003e559991469b1dbd3ac02308c5839c2a398881592dd7069c70581a92.json data/ai-cache/c2e057bd69604939a384acb7f7981b0ffca6c4ce86f493faf2fdc2690c846710.json data/ai-cache/c8194df58e7770d581a09a162b2f1ca9431577a41371f4fd327d2a1ee4188517.json data/ai-cache/d2a4a0f1be8a5302eb87834b63385bbeee7ab949a18508186dc37a1b3ad233d0.json data/demo/.gitkeep data/raw/turbine1.csv data/raw/turbine2.csv data/weather/exp_best_match.json data/weather/exp_ecmwf_ifs025.json data/weather/exp_icon_global.json data/weather/prev_cma_grapes_global.json data/weather/prev_ecmwf_ifs025.json data/weather/prev_gem_seamless.json data/weather/prev_gfs_seamless.json data/weather/prev_icon_global.json data/weather/prev_jma_seamless.json data/weather/previous_runs.json data/weather/spatial/e25.json data/weather/spatial/e50.json data/weather/spatial/n25.json data/weather/spatial/n50.json data/weather/spatial/s25.json data/weather/spatial/s50.json data/weather/spatial/w25.json data/weather/spatial/w50.json docker-compose.yml docs/api-contract.md docs/architecture.md docs/deploy.md docs/design-brief.md docs/hackathon-regulations-full.md docs/hackathon-rules.md docs/memory/README.md docs/memory/backend.md docs/playbook.md docs/progress.md docs/readme-instructions.md docs/toolbox.md frontend/.gitignore frontend/.oxlintrc.json frontend/index.html frontend/package-lock.json frontend/package.json frontend/public/favicon.svg frontend/public/partners/ai-digital-ministry.svg frontend/public/partners/astana-hub.svg frontend/public/partners/asu.svg frontend/public/partners/baitc.svg frontend/public/partners/digital-bridge.svg frontend/public/partners/hackalem.svg frontend/public/partners/mnvo.svg frontend/public/partners/nvidia.png frontend/public/partners/openai.svg frontend/public/partners/paloalto.svg frontend/public/partners/silkroad.svg frontend/src/App.css frontend/src/App.tsx frontend/src/api/client.ts frontend/src/api/endpoints.ts frontend/src/api/types.ts frontend/src/app/shared.ts frontend/src/components/BrandMark.tsx frontend/src/components/EChart.tsx frontend/src/components/ErrorBoundary.tsx frontend/src/components/LanguageSelector.tsx frontend/src/components/LoginBox.css frontend/src/components/LoginBox.tsx frontend/src/components/SiteFooter.css frontend/src/components/SiteFooter.tsx frontend/src/components/ThemeToggle.tsx frontend/src/components/ui.tsx frontend/src/features/about/AboutModal.tsx frontend/src/features/about/about.css frontend/src/features/february/AutonomousRun.tsx frontend/src/features/february/FebCalendar.tsx frontend/src/features/february/FebChart.tsx frontend/src/features/february/FebDownloads.tsx frontend/src/features/february/FebruaryTab.tsx frontend/src/features/february/febData.ts frontend/src/features/february/february.css frontend/src/features/forecast/AgentLog.tsx frontend/src/features/forecast/ControlPanel.tsx frontend/src/features/forecast/ForecastChart.tsx frontend/src/features/forecast/ForecastTab.tsx frontend/src/features/forecast/HourlyTable.tsx frontend/src/features/forecast/HowItWorks.tsx frontend/src/features/forecast/Insights.tsx frontend/src/features/forecast/KpiRow.tsx frontend/src/features/forecast/Provenance.tsx frontend/src/features/forecast/StationMap.tsx frontend/src/features/forecast/Verdict.tsx frontend/src/features/forecast/chartOption.ts frontend/src/features/forecast/forecast.css frontend/src/features/forecast/hooks.ts frontend/src/features/forecast/model.ts frontend/src/features/forecast/plain.ts frontend/src/features/forecast/rich.tsx frontend/src/features/project/ProjectTab.tsx frontend/src/features/project/project.css frontend/src/features/quality/Contrast.tsx frontend/src/features/quality/CoverageBlock.tsx frontend/src/features/quality/HoldoutCard.tsx frontend/src/features/quality/MetricsTable.tsx frontend/src/features/quality/QualityTab.tsx frontend/src/features/quality/charts.ts frontend/src/features/quality/model.ts frontend/src/features/quality/quality.css frontend/src/features/stations/StationsTab.tsx frontend/src/features/stations/UploadBox.tsx frontend/src/features/stations/stations.css frontend/src/i18n/GLOSSARY.md frontend/src/i18n/core.ts frontend/src/i18n/index.tsx frontend/src/i18n/locales/en/about.ts frontend/src/i18n/locales/en/app.ts frontend/src/i18n/locales/en/common.ts frontend/src/i18n/locales/en/february.ts frontend/src/i18n/locales/en/footer.ts frontend/src/i18n/locales/en/forecast.ts frontend/src/i18n/locales/en/index.ts frontend/src/i18n/locales/en/project.ts frontend/src/i18n/locales/en/quality.ts frontend/src/i18n/locales/en/steps.ts frontend/src/i18n/locales/kk/about.ts frontend/src/i18n/locales/kk/app.ts frontend/src/i18n/locales/kk/common.ts frontend/src/i18n/locales/kk/february.ts frontend/src/i18n/locales/kk/footer.ts frontend/src/i18n/locales/kk/forecast.ts frontend/src/i18n/locales/kk/index.ts frontend/src/i18n/locales/kk/project.ts frontend/src/i18n/locales/kk/quality.ts frontend/src/i18n/locales/kk/steps.ts frontend/src/i18n/locales/ru/about.ts frontend/src/i18n/locales/ru/app.ts frontend/src/i18n/locales/ru/common.ts frontend/src/i18n/locales/ru/february.ts frontend/src/i18n/locales/ru/footer.ts frontend/src/i18n/locales/ru/forecast.ts frontend/src/i18n/locales/ru/index.ts frontend/src/i18n/locales/ru/project.ts frontend/src/i18n/locales/ru/quality.ts frontend/src/i18n/locales/ru/steps.ts frontend/src/index.css frontend/src/lib/constants.ts frontend/src/lib/format.ts frontend/src/lib/steps.ts frontend/src/lib/theme.ts frontend/src/lib/themeManager.ts frontend/src/main.tsx frontend/tsconfig.app.json frontend/tsconfig.json frontend/tsconfig.node.json frontend/vite.config.ts outputs/calibration.json outputs/forecast_feb2026.csv outputs/forecast_feb2026_final.csv outputs/forecasts/2026-01-31_c95c39d2.json outputs/forecasts/2026-02-01_77f62bf0.json outputs/forecasts/2026-02-02_9523b8ba.json outputs/forecasts/2026-02-03_85b83973.json outputs/forecasts/2026-02-04_013a8742.json outputs/forecasts/2026-02-05_32639f5c.json outputs/forecasts/2026-02-06_62e302c0.json outputs/forecasts/2026-02-07_8e4956ed.json outputs/forecasts/2026-02-08_4e2110b3.json outputs/forecasts/2026-02-09_36e006e3.json outputs/forecasts/2026-02-10_23f1b3c4.json outputs/forecasts/2026-02-11_ab460420.json outputs/forecasts/2026-02-12_135d75a8.json outputs/forecasts/2026-02-13_0d660e33.json outputs/forecasts/2026-02-14_a011fd75.json outputs/forecasts/2026-02-15_21802606.json outputs/forecasts/2026-02-16_a03bb0b8.json outputs/forecasts/2026-02-17_458c4a8e.json outputs/forecasts/2026-02-18_936fcd32.json outputs/forecasts/2026-02-19_d8a56442.json outputs/forecasts/2026-02-20_7aea9a81.json outputs/forecasts/2026-02-21_1e014524.json outputs/forecasts/2026-02-22_ba36205c.json outputs/forecasts/2026-02-23_c8b7135d.json outputs/forecasts/2026-02-24_1245e924.json outputs/forecasts/2026-02-25_2d4fc5c5.json outputs/forecasts/2026-02-26_f5bb1220.json outputs/forecasts/2026-02-27_cc552042.json outputs/holdout_jan2026.csv outputs/holdout_jan2026.json outputs/metrics.json scripts/preflight.sh scripts/smoke.sh
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.