О проекте
Команда: ALT
Кейс HackAlem.ai: Энергетика — Самрук-Казына
Стадия: Доведённый продукт
Задача кейса: AI-агент, прогнозирующий выработку ветровой электростанции по погодным данным
Суть
Веб-приложение, которое прогнозирует нормализованную мощность двух ветровых турбин на 24 или 48 часов по архивным прогнозам погоды ECMWF IFS. Параметры можно ввести вручную или текстом через ИИ.
Как устроено
Десятиминутные наблюдения агрегируются в часовые ряды. Для каждой турбины строится сглаженная кривая мощности по прогнозной скорости ветра на 100 м (бины 0,5 м/с). Погода берётся из архивных выпусков ECMWF IFS через Open-Meteo Single Runs: выпуск должен быть инициализирован не позже чем за 12 ч до запуска, чтобы исключить утечку будущего. FastAPI валидирует запрос и сохраняет запуски в SQLite, React рисует SVG-график и таблицу. gpt-4o-mini через Responses API со строгой JSON-схемой только разбирает текстовый ввод в параметры и сам мощность не генерирует. Бустинг с расширенными признаками ведётся отдельным экспериментом и в API не подключён.
Ключевые решения
- кривая мощности (binned power curve)
- gradient boosting
- последовательный backtest
- point-in-time weather selection
- Open-Meteo Single Runs API
- structured outputs JSON schema
Метрики
MAE нормализованной мощности: кривая мощности 0,328 (дек 2025) / 0,289 (янв 2026); бустинг с расширенной погодой 0,270 / 0,244; бустинг только по ветру 0,278 / 0,221
Особенности
Честная валидация без утечки: учитывается расчётная доступность погодного выпуска к моменту запуска, backtest строго последовательный, и команда прямо оговаривает, что январь не является нетронутым тестом, а MAE не равен «точности». LLM только разбирает ввод и не выдумывает прогноз. Есть replay на 116 февральских сценариев и интерфейс на трёх языках.
Стек
Python · FastAPI · Pydantic · Uvicorn · SQLite · React 19 · TypeScript · Vite · Docker Compose · scikit-learn
Модели
gpt-4o-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-1f9ed603-alt.
README
README.mdALT Energy — почасовой прогноз мощности ветровых турбин
ALT Energy — веб-приложение, созданное для HackAlem AI на выданных организаторами датасетах. Оно строит прогноз нормализованной активной мощности двух ветровых турбин на 24 или 48 часов с шагом один час. Пользователь задаёт турбину, момент исторического запуска и горизонт вручную или текстом через ИИ. Система применяет обученную модель к архивному прогнозу ветра и показывает результат вместе с происхождением погоды и версией модели.
Быстрый пример: турбина 1, запуск 2026-02-01T12:00:00Z, горизонт 48 часов. Обученные модели и необходимый погодный кэш уже включены в репозиторий; для первого ручного расчёта переобучение и ключ OpenAI не нужны. Февральский replay содержит 116 сценариев: 29 ежедневных запусков в 12:00 UTC с 31 января по 28 февраля, две турбины и два горизонта.
Что реализовано
- Два режима ввода: «Вручную» и «Спросить ИИ», с выбором турбины и горизонта в обоих режимах. ИИ разбирает текстовую дату и параметры, после чего интерфейс запускает обычное прогнозное ядро; неоднозначный ввод требует уточнения.
- Интерфейс на русском, казахском и английском с сохранением выбранного языка.
- Интерактивный график с выбором часа, почасовая таблица, минимум, среднее и максимум прогнозной мощности; отдельное окно со сведениями об исходных CSV и пропусках.
- Подготовка десятиминутных наблюдений в часовые ряды, обучение отдельной кривой мощности для каждой турбины и выбор версии модели без использования будущих наблюдений.
- Получение архивного погодного выпуска ECMWF IFS, проверка его расчётной доступности к моменту запуска и вывод происхождения погоды вместе с прогнозом.
- HTTP API с валидацией запроса и результата, сохранением успешных запусков в SQLite, февральский replay на 116 запусков и последовательная проверка на декабре–январе.
- Воспроизводимый эксперимент с расширенными погодными признаками. Экспериментальная модель пока не подключена к API.
Технологии и архитектура
Frontend: React 19, TypeScript 5.8, Vite 8 и Lucide; график реализован на SVG. Backend: Python, FastAPI, Pydantic и Uvicorn; прогнозное ядро также написано на Python. Для хранения запусков используется SQLite — локальный файл, которому не нужен отдельный сервер БД. Совместный локальный запуск выполняется через Docker Compose. Текстовый ввод использует OpenAI Responses API со строгой JSON-схемой. scikit-learn нужен только для отдельного эксперимента. Зависимости указаны в backend/requirements.txt, backend/requirements-test.txt, frontend/package.json и forecasting/requirements-experiment.txt.
Ручной ввод ────────────────────────────→ параметры прогноза
Текст → FastAPI → OpenAI Responses ────→ параметры прогноза
│
FastAPI /forecast-runs
│
forecasting.runner
│ │
модель JSON архив ECMWF IFS
│
проверка → SQLite
│
график и таблица
| Папка | Ответственность |
|---|---|
backend/ | HTTP API, валидация, проверка временных границ, сохранение успешных запусков |
frontend/ | Выбор параметров, график и таблица почасового прогноза, ошибки |
forecasting/ | Подготовка часовых рядов, погодный архив, обучение и расчёт модели |
data/raw/ | Два исходных CSV, выданных организаторами |
data/processed/ | Часовые ряды, манифест исторических запусков и отчёт проверки |
data/weather/ | Сохранённые ответы архива погоды |
shared/API.md | Формат запросов и ответов между участниками |
При текстовом вводе frontend сначала получает проверенные параметры, затем вызывает тот же endpoint прогноза, что и ручная форма. ИИ не генерирует значения мощности. В OpenAI передаются текст пользователя и выбранные параметры; CSV и прогнозные ряды не передаются. Ключ используется только на backend.
Данные и модель
Исходные CSV организаторов сохранены без изменений и содержат десятиминутные наблюдения двух турбин с 11 марта 2023 года по 31 января 2026 года: время, скорость ветра, температуру и нормализованную активную мощность. Февраль 2026 года — период исторического воспроизведения прогнозов; фактических значений мощности за февраль в репозитории нет. Целевая величина находится в диапазоне 0–1 и не является кВт·ч.
| Файл | Наблюдений | Пропущенных десятиминутных интервалов |
|---|---|---|
data/raw/turbine_1.csv | 142 360 | 9 992 |
data/raw/turbine_2.csv | 149 499 | 2 853 |
Шесть записей HH:00–HH:50 образуют среднее за час, обозначенный концом HH+1:00. Для действующей модели используются сопоставленные примеры ноября 2025 — января 2026, а не весь многолетний CSV. Кривая строится отдельно для каждой турбины по интервалам скорости 0,5 м/с; редкие интервалы сглаживаются к среднему обучающего ряда.
Подготовка данных формирует часовую сетку и сохраняет пропуски. Для обучения используются только полные часы с известной мощностью. Текущая базовая модель — сглаженная зависимость мощности от прогнозной скорости ветра на высоте 100 м. Прогнозы ветра взяты из отдельных архивных запусков ECMWF IFS через Open-Meteo Single Runs; код выбирает выпуск, инициализированный не позже чем за 12 часов до расчёта. Время инициализации модели погоды и расчётный порог доступности отдельно показаны в API, интерфейсе и манифесте. Фактическое время публикации в архиве неизвестно; подробности — в forecasting/README.md.
Исходные метки времени используются как в датасете, без прибавления или вычитания часового пояса. Для соединения с погодой одинаковые календарные даты и часы сопоставляются напрямую с осью API. В моделях и отчётах записано time_alignment.policy = as_provided_no_shift. Это принятое правило обработки предоставленных данных. API принимает явное смещение или Z и возвращает UTC. Первая точка прогноза соответствует часу, заканчивающемуся через час после запуска.
Качество модели
Проверка последовательная: ноябрь → декабрь, ноябрь–декабрь → январь. Целевые часы обучения строго предшествуют проверяемому периоду. MAE — средняя абсолютная ошибка нормализованной мощности; меньше лучше. Значение 0,328 означает отклонение в среднем на 32,8 процентного пункта шкалы 0–1, а не «точность 67,2%».
| Модель | Декабрь 2025, MAE | Январь 2026, MAE | Использование |
|---|---|---|---|
| Сглаженная кривая мощности | 0,32776 | 0,28852 | Действующая модель API |
| Бустинг: расширенная погода и производные признаки | 0,26998 | 0,24369 | Эксперимент, выбран по декабрю |
| Бустинг: ветер и временные производные | 0,27844 | 0,22097 | Контрольное сравнение |
Метрики объединяют обе турбины и горизонты 1–24 и 1–48 часов; часть целевых часов учитывается повторно. Январь уже использовался для анализа проекта и не является новым нетронутым тестом. Расширенный вариант улучшает ошибку относительно действующей модели, но польза именно новых погодных величин нестабильна: в январе контрольный вариант лучше. Эксперимент не заменяет модель приложения.
Подробности: backtest_report.json, аудит прогнозов, эксперимент с архивными признаками. Ошибку за февраль по предоставленным файлам вычислить нельзя.
Установка и запуск
Для локального запуска нужны Python 3.11+ и Node.js версии ^20.19.0 или >=22.12.0. Для контейнерного запуска достаточно Docker с Compose. Интернет нужен для установки зависимостей, режима ИИ и погодных выпусков, которых нет в локальном кэше. Ключ API для реализованного погодного запроса не требуется. Начните с клонирования:
git clone https://github.com/BAITC-Hacks/hack-1f9ed603-alt.git
cd hack-1f9ed603-alt
Локально
В первом терминале, из корня репозитория:
python -m venv .venv
.\.venv\Scripts\python -m pip install -r backend\requirements.txt
# Выполните один раз, если .env ещё не создан:
Copy-Item .env.example .env
# Заполните OPENAI_API_KEY в .env для режима ИИ (ручной режим работает без ключа).
.\.venv\Scripts\python -m uvicorn backend.app.main:app --reload --port 8000 --env-file .env
На macOS/Linux команды первого терминала:
python3 -m venv .venv
.venv/bin/python -m pip install -r backend/requirements.txt
# Выполните один раз, если .env ещё не создан:
cp .env.example .env
.venv/bin/python -m uvicorn backend.app.main:app --reload --port 8000 --env-file .env
Если .env уже существует, сохраните его настройки вместо повторного копирования. Ключ хранится только на backend и не включается в frontend. Во втором терминале, из корня репозитория:
cd frontend
npm ci
npm run dev
Откройте http://localhost:5173. Документация API: http://localhost:8000/docs. Vite проксирует /api к http://localhost:8000.
Настройки окружения
| Переменная | Назначение |
|---|---|
OPENAI_API_KEY | Серверный ключ для «Спросить ИИ»; ручной режим работает без него |
OPENAI_MODEL | По умолчанию gpt-4o-mini; нужен Responses API и поддержка строгой JSON-схемы |
DATA_DIR | CSV для сведений о турбинах в API; по умолчанию data/raw |
RUNS_DB_PATH | SQLite успешных расчётов; локально backend/runs.sqlite3 |
VITE_API_PROXY_TARGET | Адрес backend для Vite; локально http://localhost:8000 |
Backend читает .env через --env-file; Compose передаёт ключ и модель из корневого .env или окружения. Для изменения локального прокси задайте VITE_API_PROXY_TARGET в окружении терминала frontend перед npm run dev: например, $env:VITE_API_PROXY_TARGET="http://localhost:8001" в PowerShell. Корневой .env автоматически процессом Vite не загружается. DATA_DIR не меняет пути обучения и артефактов прогнозного ядра; сохраняйте стандартную структуру проекта. .env исключён из Git и Docker-образов; не используйте префикс VITE_ для секретов.
Docker
Если установлен Docker с Compose, вместо двух локальных серверов выполните из корня репозитория. Для ручного режима .env не обязателен; для ИИ предварительно создайте его из .env.example и заполните ключ:
docker compose up --build
Интерфейс откроется на http://localhost:5173, документация API — на http://localhost:8000/docs. Исходные CSV монтируются в контейнер backend без записи. Сохранённые погодные выпуски монтируются из data/weather/ecmwf_ifs/; новые выпуски backend может добавить в эту папку через внешний API, поэтому для дат вне кэша нужна сеть. Успешные расчёты хранятся в именованном томе runs_data и сохраняются при пересоздании контейнера и обычном docker compose down. Команда docker compose down -v удаляет этот том.
Проверки и воспроизводимость
Команды Python выполняются из корня в созданном окружении. Если оно не активировано, вместо python используйте .\.venv\Scripts\python.exe на Windows или .venv/bin/python на macOS/Linux.
python -m pip install -r backend/requirements-test.txt
python -m unittest discover -s forecasting/tests -v
python -m unittest discover -s backend/tests -v
Frontend:
cd frontend
npm ci
npm test
npm run build
Для пересоздания моделей и отчётов, из корня:
python -m forecasting.train_baseline
python -m forecasting.replay_february
python -m forecasting.audit
Эти команды перезаписывают генерируемые артефакты и отчёты. Используется локальный погодный кэш; отсутствующие выпуски запрашиваются у Open-Meteo. Для обычного запуска приложения повторное обучение не требуется. Подробности — в forecasting/README.md.
Отдельный эксперимент с расширенной погодой:
python -m pip install -r forecasting/requirements-experiment.txt
python -m forecasting.experiment_features
Эксперимент работает офлайн на выданных CSV и 92 сохранённых погодных запусках, записывает data/processed/feature_experiment.json и не заменяет действующую модель.
Проверить основной сценарий
- Откройте интерфейс и убедитесь, что отображаются обе турбины и количество наблюдений.
- Выберите турбину 1, горизонт 48 часов и введите
2026-02-01T12:00:00Z. - Нажмите «Построить прогноз». Ожидаемый результат — график и таблица из 48 значений: от
2026-02-01T13:00:00Zдо2026-02-03T12:00:00Z. - В блоке «Источник и параметры запуска» проверьте время инициализации погодной модели, расчётный порог её доступности, идентификатор погодного запуска и версию модели.
Для текстового ввода при настроенном ключе откройте «Спросить ИИ», выберите турбину и горизонт и введите «22 февраля 17:00 2026 года». Форма получит 2026-02-22T17:00:00Z, а график и таблица будут построены обычной моделью. Первая точка — 18:00. Если турбина или горизонт указаны в тексте, они заменяют выбранные значения; иначе используются параметры формы. Время без явно указанного пояса не сдвигается. Неполная дата, отсутствующий год или неподдерживаемый горизонт требуют уточнения.
Ручной запрос через API на macOS/Linux:
curl -X POST http://localhost:8000/api/forecast-runs \
-H "Content-Type: application/json" \
-d '{"turbine_id":"turbine_1","issued_at":"2026-02-01T12:00:00Z","horizon_hours":48}'
PowerShell:
Invoke-RestMethod http://localhost:8000/api/health
$body = '{"turbine_id":"turbine_1","issued_at":"2026-02-01T12:00:00Z","horizon_hours":48}'
$result = Invoke-RestMethod -Method Post -Uri http://localhost:8000/api/forecast-runs -ContentType 'application/json' -Body $body
$result.points.Count # 48
$result.points[0]
$result.points[-1]
Успех — HTTP 201, status: completed, уникальный run_id, 48 почасовых точек в диапазоне 0–1 и сохранённый расчёт в SQLite. Полная структура — в shared/API.md.
| Endpoint | Назначение |
|---|---|
GET /api/health | Проверка доступности процесса API; не полная диагностика зависимостей |
GET /api/turbines | Координаты и сводка исходных CSV |
POST /api/forecast-runs | Расчёт и сохранение прогноза |
POST /api/assistant/forecast-parameters | Разбор текста: ready с параметрами либо clarification с уточнением |
Ошибки имеют формат {"error":"сообщение"}. Неверный запрос возвращает 422; отсутствие модуля прогнозного ядра — 501; некорректный ответ ядра/ИИ — 502; недоступные данные, погода, хранилище или сервис ИИ — 503; внутренняя ошибка — 500. Ручной режим не зависит от OpenAI. При ошибке прогноз не подменяется вымышленными значениями.
Известные ограничения
- Прогнозируемая величина — доля нормализованной активной мощности от 0 до 1. Без номинальной мощности турбин её нельзя корректно перевести в кВт или кВт·ч.
- Основной проверенный сценарий — исторические запуски. Для
2026-01-31T12:00:00Zиспользуется отдельная модель, обученная до запуска; с 1 февраля доступна финальная модель. Более ранние даты требуют отдельно обученного артефакта. Постоянного переобучения на текущих наблюдениях нет. - Февральский replay сохраняет результаты и происхождение погоды в
data/processed/february_replay.json. Фактической мощности за февраль в предоставленных файлах нет, поэтому ошибку этих прогнозов здесь оценить нельзя. - Фактическое историческое время публикации погодного выпуска архив не предоставляет; используется консервативное правило доступности через 12 часов после инициализации.
- Исходные метки CSV используются без сдвига; группировка десятиминутных записей по часам — принятое правило обработки, сохранённое в артефактах.
- Прогноз погоды использует ветер на высоте 100 м. Обе турбины попадают в одну погодную ячейку архива, поэтому локальные различия ветра моделью погоды не разрешаются.
- Модель основана на статистической кривой «скорость ветра → мощность»; редкие экстремальные скорости, остановки и ограничения работы турбины она не воспроизводит надёжно. Результаты аудита — в data/processed/validation_report.json.
- На Windows обнаружен отказ доступа при конкурентном чтении/обновлении погодного кэша: соответствующий тест завершается
PermissionError. Ошибка воспроизведена и вне песочницы; общий набор тестов прогнозирования сейчас не полностью проходит. - Режиму ИИ нужны сеть, действующий серверный ключ и доступный лимит OpenAI. Распознанные параметры показываются пользователю; неполные и неоднозначные запросы требуют уточнения. Это помощник для ввода параметров, а не универсальный чат или управление турбинами.
- В SQLite сохраняются успешные расчёты, но интерфейс истории не реализован. Нет авторизации и ограничения частоты запросов. Compose предназначен для локального запуска и использует Vite dev server.
Развёрнутая версия
Публичный URL приложения в репозитории не указан. Проект запускается локально по инструкции выше.
Отчёт проверки — 23 сентября 2026
При подготовке этой редакции README проверена текущая реализация на Windows с Python 3.13 и Node.js 24.12:
| Проверка | Результат |
|---|---|
| Backend unittest | 29 тестов пройдено, включая все 116 сценариев replay через API |
| Forecasting unittest | 27 из 28 пройдено; конкурентный доступ к погодному кэшу завершился PermissionError |
npm ci | Зависимости установлены по lock-файлу |
npm test | 8 тестов пройдено |
npm run build | Проверка TypeScript и сборка Vite успешны |
Backend-тесты используют настоящее прогнозное ядро, архивную погоду и временную SQLite. Ответ OpenAI подменяется только в автоматических тестах. Docker, браузер и реальный сетевой вызов OpenAI в этой проверке повторно не запускались. Предыдущие проверки команды с реальным OpenAI и браузером описаны в backend/AI_QA.md; более ранняя проверка интеграции — в backend/QA.md.
Использованные материалы
- Условие задачи и исходные CSV предоставлены организаторами HackAlem AI.
- Погодные данные: ECMWF IFS через Open-Meteo Single Runs, условия использования и атрибуции — Open-Meteo Terms.
- OpenAI Responses API используется только для текстового ввода; настройка и поведение описаны в backend/README.md. Реализация задаёт
store: false, таймаут 30 секунд и повторно проверяет структурированный ответ. - Библиотеки перечислены в
backend/requirements.txtиfrontend/package.json. - При разработке использовался OpenAI Codex.
Авторы коммитов
История коммитов
- 2026-09-23 17:40docs: finalize ALT Energy product READMEkorolbbichey
- 2026-09-23 17:23feat(frontend): add forecast selectors to AI setup and simplify contextTemirlan Abugali
- 2026-09-23 17:09feat: connect AI date input to the forecasting workflowАзиз
- 2026-09-23 16:52chore(frontend): rename product to ALT EnergyTemirlan Abugali
- 2026-09-23 16:49feat(frontend): add manual and AI demo setup modesTemirlan Abugali
- 2026-09-23 16:46Evaluate extended archived weather on supplied turbine datasetskorolbbichey
- 2026-09-23 16:36feat(frontend): build multilingual forecast workspaceTemirlan Abugali
- 2026-09-23 16:21docs: complete project README for handoffkorolbbichey
Все коммиты (24)
- 2026-09-23 16:13Use dataset clock labels without timezone conversionАзиз
- 2026-09-23 15:51Harden forecasting integration and audit prediction realismАзиз
- 2026-09-23 15:49feat(frontend): refine forecast dashboard designTemirlan Abugali
- 2026-09-23 15:29docs: complete final integration QA and task statuskorolbbichey
- 2026-09-23 15:16docs: verify and complete forecasting tasks F1 and F2Азиз
- 2026-09-23 15:08feat: expose weather run availability provenancekorolbbichey
- 2026-09-23 14:59docs: mark backend and Docker tasks completekorolbbichey
- 2026-09-23 14:54Complete point-in-time forecasting and February replayАзиз
- 2026-09-23 14:54fix: validate forecast hours and persist Docker runskorolbbichey
- 2026-09-23 14:53feat(frontend): validate demo forecast launch timeTemirlan Abugali
- 2026-09-23 14:43docs: update project status and assign QA taskskorolbbichey
- 2026-09-23 14:31feat(forecasting): add archived-weather baseline and backtestsАзиз
- 2026-09-23 14:20feat(frontend): display hourly forecast and weather provenanceTemirlan Abugali
- 2026-09-23 14:15feat: validate and store forecast runs in backendkorolbbichey
- 2026-09-23 14:03docs: finalize turbine coordinates and forecast API contractkorolbbichey
- 2026-09-23 13:51chore: scaffold wind forecasting projectkorolbbichey
Структура репозитория (297 файлов)
.dockerignore .env.example .gitignore AGENTS.md README.md TASKS.md backend/.gitignore backend/AGENTS.md backend/AI_QA.md backend/Dockerfile backend/QA.md backend/README.md backend/__init__.py backend/app/__init__.py backend/app/assistant_service.py backend/app/db.py backend/app/forecast_service.py backend/app/main.py backend/app/schemas.py backend/requirements-test.txt backend/requirements.txt backend/tests/__init__.py backend/tests/test_api_integration.py backend/tests/test_assistant.py backend/tests/test_forecast_service.py compose.yaml data/processed/backtest_report.json data/processed/feature_experiment.json data/processed/february_replay.json data/processed/historical_launches.json data/processed/hourly_turbine_1.csv data/processed/hourly_turbine_2.csv data/processed/validation_report.json data/raw/turbine_1.csv data/raw/turbine_2.csv data/weather/ecmwf_ifs/ecmwf_ifs_20251101T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251102T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251103T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251104T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251105T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251106T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251107T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251108T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251109T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251110T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251111T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251112T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251113T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251114T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251115T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251116T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251117T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251118T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251119T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251120T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251121T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251122T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251123T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251124T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251125T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251126T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251127T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251128T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251129T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251130T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251201T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251202T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251203T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251204T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251205T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251206T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251207T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251208T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251209T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251210T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251211T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251212T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251213T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251214T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251215T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251216T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251217T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251218T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251219T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251220T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251221T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251222T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251223T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251224T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251225T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251226T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251227T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251228T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251229T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251230T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20251231T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260101T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260102T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260103T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260104T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260105T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260106T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260107T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260108T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260109T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260110T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260111T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260112T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260113T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260114T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260115T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260116T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260117T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260118T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260119T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260120T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260121T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260122T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260123T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260124T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260125T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260126T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260127T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260128T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260129T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260130T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260131T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260201T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260202T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260203T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260204T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260205T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260206T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260207T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260208T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260209T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260210T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260211T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260212T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260213T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260214T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260215T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260216T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260217T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260218T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260219T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260220T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260221T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260222T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260223T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260224T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260225T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260226T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260227T0000Z.json data/weather/ecmwf_ifs/ecmwf_ifs_20260228T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251101T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251102T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251103T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251104T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251105T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251106T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251107T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251108T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251109T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251110T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251111T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251112T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251113T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251114T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251115T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251116T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251117T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251118T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251119T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251120T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251121T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251122T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251123T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251124T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251125T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251126T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251127T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251128T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251129T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251130T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251201T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251202T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251203T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251204T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251205T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251206T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251207T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251208T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251209T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251210T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251211T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251212T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251213T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251214T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251215T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251216T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251217T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251218T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251219T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251220T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251221T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251222T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251223T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251224T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251225T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251226T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251227T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251228T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251229T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251230T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20251231T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260101T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260102T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260103T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260104T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260105T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260106T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260107T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260108T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260109T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260110T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260111T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260112T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260113T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260114T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260115T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260116T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260117T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260118T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260119T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260120T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260121T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260122T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260123T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260124T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260125T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260126T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260127T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260128T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260129T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260130T0000Z.json data/weather/ecmwf_ifs_features/ecmwf_ifs_20260131T0000Z.json forecasting/AGENTS.md forecasting/FEATURE_EXPERIMENT.md forecasting/README.md forecasting/__init__.py forecasting/artifacts/baseline_model.json forecasting/artifacts/baseline_pre_20260131T1200Z.json forecasting/audit.py forecasting/baseline.py forecasting/dataset.py forecasting/experiment_features.py forecasting/feature_weather.py forecasting/forecast.py forecasting/hourly.py forecasting/inspect_data.py forecasting/replay_february.py forecasting/requirements-experiment.txt forecasting/runner.py forecasting/sites.py forecasting/storage.py forecasting/tests/test_feature_experiment.py forecasting/tests/test_forecasting.py forecasting/tests/test_validation.py forecasting/time_alignment.py forecasting/train_baseline.py forecasting/weather.py frontend/AGENTS.md frontend/Dockerfile frontend/index.html frontend/package-lock.json frontend/package.json frontend/public/favicon.svg frontend/public/images/wind-dusk.jpg frontend/public/images/wind-sunset.jpg frontend/src/App.tsx frontend/src/AssistantPanel.css frontend/src/AssistantPanel.tsx frontend/src/ForecastResult.css frontend/src/ForecastResult.tsx frontend/src/ForecastSelectors.tsx frontend/src/api.ts frontend/src/assistantMessages.ts frontend/src/forecastMessages.ts frontend/src/i18n.tsx frontend/src/main.tsx frontend/src/messages.ts frontend/src/style.css frontend/tests/api.test.mjs frontend/tsconfig.json frontend/vite.config.ts shared/API.md
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.