No description
  • Python 97.6%
  • Dockerfile 2.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-20 16:28:52 +02:00
examples first commit 2026-10-20 16:28:52 +02:00
forecast_service first commit 2026-10-20 16:28:52 +02:00
scripts first commit 2026-10-20 16:28:52 +02:00
tests first commit 2026-10-20 16:28:52 +02:00
.dockerignore first commit 2026-10-20 16:28:52 +02:00
.editorconfig first commit 2026-10-20 16:28:52 +02:00
.env.example first commit 2026-10-20 16:28:52 +02:00
.gitattributes first commit 2026-10-20 16:28:52 +02:00
.gitignore first commit 2026-10-20 16:28:52 +02:00
compose.yaml first commit 2026-10-20 16:28:52 +02:00
Dockerfile first commit 2026-10-20 16:28:52 +02:00
README.md first commit 2026-10-20 16:28:52 +02:00
requirements-dev.txt first commit 2026-10-20 16:28:52 +02:00
requirements.txt first commit 2026-10-20 16:28:52 +02:00
VERIFICATION.md first commit 2026-10-20 16:28:52 +02:00

Forecast Benchmark

Samodzielny serwis do testów treningu, wersjonowania, predykcji i odbioru wyników. Obejmuje prices, demand, pv, fw i oze (oze uruchamia PV i wiatr). Nie wymaga importowania projektu nadrzędnego, Databricks, kolejek ani istniejących modeli. W paczce nie ma danych źródłowych, sekretów ani modeli produkcyjnych.

Struktura repozytorium

forecast_service/     API, pipeline treningu, modele i adaptery danych
forecast_service/sql/ Parametryzowane zapytania do istniejącego schematu SQL
examples/            Payloady train/predict i syntetyczne przykłady wyników
scripts/run_demo.py  Kompletny demonstracyjny przebieg wszystkich obszarów
tests/               Testy integracyjne i kontraktowe
.env.example         Konfiguracja bez sekretów
Dockerfile           Obraz serwisu z LightGBM i sterownikiem ODBC
compose.yaml         Lokalne uruchomienie kontenera z trwałym wolumenem

Szybki start

Python 3.10–3.12. Polecenia wykonuj w tym folderze:

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
Copy-Item .env.example .env
.\.venv\Scripts\python.exe -m uvicorn forecast_service.api:app --host 127.0.0.1 --port 8000 --workers 1 --no-access-log

Opis API i interaktywny formularz: http://127.0.0.1:8000/docs. Domyślnie DATA_SOURCE=synthetic: dane są generowane matematycznie, a modele naprawdę się trenują. Odpowiedź zawsze podaje źródło danych. Błąd SQL nigdy nie przełącza na dane syntetyczne.

W drugim terminalu, w tym samym folderze:

$trained = Invoke-RestMethod http://127.0.0.1:8000/train -Method Post -ContentType application/json -Body (Get-Content examples/train_prices.json -Raw)
$predicted = Invoke-RestMethod http://127.0.0.1:8000/predict -Method Post -ContentType application/json -Body (Get-Content examples/predict_prices.json -Raw)
$predicted
Invoke-WebRequest ("http://127.0.0.1:8000" + $predicted.outputs[0].url) -OutFile forecast.csv

Analogicznie użyj train_demand.json, predict_demand.json, train_oze.json i predict_oze.json. Aby uruchomić PV albo wiatr osobno, ustaw stage na pv lub fw. Model wytrenowany przez oze obsługuje też osobne predykcje pv i fw.

Kompletny test wszystkich obszarów bez serwera i bez dostępu do baz:

.\.venv\Scripts\python.exe scripts/run_demo.py --quick

Bez --quick wykona się pełny wariant 1500 iteracji × 3 ziarna. Demo jawnie używa danych syntetycznych, niezależnie od .env, i zapisuje wyniki oraz modele w outputs/demo/. Modele demo nie są automatycznie publikowane w rejestrze API.

Model i obliczenia

Każdy target ma ensemble trzech modeli LightGBM: domyślnie 1500 iteracji, 90 liści, głębokość 10, uczenie 0.025, próbkowanie cech i wierszy oraz regularyzację. Ceny mają trzy targety: Fix1, Fix2, RB; pozostałe obszary po jednym. Pełny trening wszystkich obszarów tworzy 18 modeli.

Cechy: kalendarz, cykle dobowe i roczne, pogoda, moc zainstalowana, opóźnienia 24/48/72/168 h oraz średnie i odchylenia kroczące. Modele PV/FW są wspólne dla punktów danej technologii; identyfikatory i współrzędne nie są cechami.

Walidacja odbywa się po okresie treningowym. Prognoza działa w blokach do 24 h: przyszłe wartości rzeczywiste są usuwane, a dalsze opóźnienia korzystają z prognoz. Raport zawiera MAE, RMSE, liczbę obserwacji oraz pokrycie walidacji. Brak wystarczających danych powoduje błąd.

Można zmienić obciążenie w payloadzie treningu:

{
  "type": "train",
  "stage": "oze",
  "train_start": "2026-01-01",
  "train_end": "2026-04-01",
  "valid_start": "2026-04-01",
  "valid_end": "2026-04-08",
  "parameters": {
    "rounds": 2000,
    "num_leaves": 90,
    "max_depth": 10,
    "learning_rate": 0.025,
    "seeds": [42, 43, 44]
  }
}

Liczbę wątków ustawia MODEL_THREADS (domyślnie 2). Zapis modeli: natywne pliki LightGBM .txt i manifest .json. Żadna ścieżka aplikacji nie odczytuje ani nie zapisuje pickle/joblib.

Endpointy i kontrakt

Metoda i ścieżka Działanie
GET /health Stan procesu i źródło danych
GET /ready Gotowość API i liczba zapisanych zestawów modeli; bez sprawdzania połączenia SQL
POST /train Trening, walidacja, zapis modeli i CSV z walidacji
POST /predict Predykcja z zapisanej wersji i eksport CSV
POST /jobs Te same operacje, rozdzielane polem type
GET /runs/{run_id} Wynik ukończonego zadania, metryki i lista plików
GET /runs/{run_id}/{filename} Pobranie pliku wynikowego

Zadania są synchroniczne. Jeden proces wykonuje jedno zadanie naraz; kolejne dostaje HTTP 409. Na platformie ustaw odpowiedni timeout albo uruchamiaj CLI jako zadanie kontenerowe:

python -m forecast_service examples/train_prices.json
python -m forecast_service examples/predict_prices.json

CLI wypisuje JSON i zwraca niezerowy kod przy błędzie. Podstawowe pola to type, stage, model_name, model_version, save_model i zakresy dat. Nieobsługiwane opcje powodują HTTP 422. model_name to etykieta własnego treningu, domyślnie benchmark; nie wybiera starych strategii rynkowych. Przy predykcji musi odpowiadać treningowi.

Wszystkie okna są półotwarte [od, do), według Europe/Warsaw. 2026-04-08 → 2026-04-09 oznacza jeden dzień. train_end <= valid_start; minimum treningu to 14 dni, maksimum prognozy/walidacji wraz z przerwą to 31 dni. Przy braku dat trening obejmuje 180 dni, potem 7 dni walidacji; predykcja bez dat obejmuje jutro.

Predykcja wymaga wcześniejszego treningu. Bez model_version wybierany jest najnowszy kompletny zestaw dla danego źródła danych, nazwy i obszaru. model_version zwrócone przez trening pozwala przypiąć konkretną wersję. Nie można prognozować dat wcześniejszych od końca treningu wybranego modelu. save_model=false daje walidację i wyniki bez rejestracji modelu. Zmiana źródła, tabel lub klucza pseudonimizacji wymaga ponownego treningu.

Wyniki

outputs/<run_id>/ zawiera CSV i result.json. API zwraca metryki, wersję modelu, liczbę wierszy, linki i po trzy wiersze podglądu. Eksporty mają nagłówki zgodne z podstawowymi eksportami projektu:

Obszar Najważniejsze kolumny
Ceny DatetimePolska, DatetimeUTC, RetrievalTimestampUTC, Rozdzielczosc, Fix1_pred, Fix2_pred, RB_pred
Zapotrzebowanie PredZuzycieMWh, Actual, WolumenRoczny, TrainingCutoffLabel, Model, ModelName i znaczniki czasu
PV/wiatr EnergyGenerationSiteId, EnergyMeteringPointId, EnergyMeteringPointCode, ForecastMWh, GenerationTechnologyCode, SignatureUTC, Model i pozostałe pola bazowego eksportu produkcji

Gotowe przykłady wszystkich czterech obszarów są w examples/output/. Powstały z pełnego treningu na danych syntetycznych; run_report.json zawiera metryki i czasy tego przebiegu. Nie trzeba trenować modelu, żeby obejrzeć format.

output_resolutions: "60", "15" albo "60,15" (domyślnie). Każda rozdzielczość ma osobny plik. Prognoza jest godzinowa; kwadranse są rozwinięciem: ceny są powtarzane, energia w MWh dzielona przez 4. To nie jest natywny model kwadransowy. Godziny wyznaczane są w UTC, więc doby zmiany czasu mają 23/25 godzin i 92/100 kwadransów. Do jednoznacznego łączenia wyników używaj DatetimeUTC.

W demand pola Actual i WolumenRoczny są puste — nie eksportujemy pomiarów ani wolumenów kontraktowych. Rzeczywiste wartości walidacji służą tylko metrykom. W PV/FW Latitude, Longitude, PowerCurveId, PriceHedgingType i IncludeInPortfolio są puste. Pole lokalizacji reprezentuje anonimowy punkt pomiarowy, nie oryginalny podział na wiele instalacji. Nie należy sumować plików 15- i 60-minutowych ze sobą.

Te same bazy danych

W .env lub sekretach platformy ustaw:

DATA_SOURCE=sql
DB_HOST=<adres-twojego-serwera>
DB_NAME=<nazwa-twojej-bazy>
DB_AUTH=azure
ANONYMIZATION_KEY=<wlasny-staly-losowy-sekret-minimum-32-znaki>

Nie są kopiowane istniejące .env, magazyny sekretów ani adresy. Połączenie używa ODBC Driver 18, szyfrowania i weryfikacji certyfikatu. DB_AUTH=azure obsługuje standardowy łańcuch Azure Identity, a komplet AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET wybiera service principal. Alternatywnie DB_AUTH=sql oraz DB_USER i DB_PASSWORD. Zasobowi przydziel dostęp do odczytu; aplikacja wykonuje wyłącznie zapytania SELECT.

Zapytania znajdują się w forecast_service/sql/. Zostają nazwy tabel i kolumn, bo mają pasować do tego samego schematu:

Dane Domyślne tabele
Ceny dbo.tge_rdn_kontrakty, dbo.ceny_rynek_bilansujacy
Zapotrzebowanie dbo.iris_zuzycie_rozbicie, dbo.pricing_report, dbo.excluded_clients
PV i wiatr dbo.generation_unit, dbo.energy_generation_site, dbo.energy_metering_point_mapping, dbo.iris_zuzycie_rozbicie
Pogoda dbo.meteo_unified_model_4

Zmienne TABLE_* z .env.example pozwalają wskazać schemat.tabela lub baza.schemat.tabela. Wartości dat są parametrami zapytań; identyfikatory tabel przechodzą walidację. Odczyt poboru używa Kierunek=1, produkcji Kierunek=2, technologii PV 2, wiatru 1, zgodnie z zastanym kodem.

Wersja minimalna agreguje pogodę i dane do godzin. Wybiera ostatnią prognozę pogody dostępną do D-1 08:30, dodatkowo ograniczoną datą rozpoczęcia predykcji. Brak pogody pozostaje wartością brakującą obsługiwaną przez LightGBM. Metadane jednostek są aktualnym stanem bazy, a nie pełnym historycznym snapshotem.

Tabele źródłowe podają czas lokalny bez offsetu. Zapytania agregują powtarzającą się jesienną godzinę, a adapter przypisuje ten sam agregat do obu godzin UTC. To ograniczenie testowego adaptera: precyzyjny historyczny backtest wymaga źródłowego UTC lub oznaczenia powtórzonej godziny. Eksport prognoz ma jednoznaczny UTC.

Anonimizacja i granice zakresu

  • Nazwy organizacji, hosty, ścieżki użytkowników, identyfikatory chmury, dane klientów i istniejące artefakty nie są częścią paczki.
  • Punkty PV/FW dostają stabilny pseudonim HMAC-SHA256 z własnym kluczem. Jawne identyfikatory nie są zapisywane do plików ani używane jako cechy.
  • Logi błędów nie zawierają treści zapytań, parametrów połączenia ani tracebacków.
  • Dane SQL nadal opisują rzeczywisty biznes. Ich prognozy, metryki i wyuczone modele mogą ujawniać zależności lub skalę działalności. To pseudonimizacja i ograniczenie metadanych, nie gwarancja pełnej anonimowości wartości liczbowych. Do publicznej prezentacji służy jawny tryb syntetyczny.

To reprezentatywny workload MLOps, a nie odtworzenie jakości modeli produkcyjnych. Wspólny model drzewiasty zastępuje ensemble biznesowe, modele fizyczne i sieci neuronowe. Nie ma taryfowych wariantów demand, RUS, direction/spread, redispatch, aktywacji jednostek, procesów kolejkowych, zapisów do tabel wynikowych ani publikacji w chmurze. Zachowany jest przepływ trening → wersja → predykcja → CSV dla wszystkich czterech obszarów.

Uruchomienie w kontenerze

Copy-Item .env.example .env
docker compose up --build

Obraz zawiera sterownik ODBC zgodnie z instrukcją Microsoft. Podczas instalacji sterownika akceptuje jego licencję. Kontener działa jako użytkownik 10001; dane zapisuje w /data. Plik .dockerignore dopuszcza wyłącznie kod serwisu i requirements.

Na platformie buduj z tego folderu, ustaw sekrety, zamontuj zapisywalny wolumen pod /data i uruchom jeden proces API. Kolejkowanie i skalowanie zadań pozostają po stronie platformy. Artefakty mają niezmienne wersje i manifest zapisany na końcu, więc można przenieść je do magazynu platformy. Usługa nie rejestruje ich automatycznie w zewnętrznym rejestrze. HTTP zakłada prywatny dostęp lub uwierzytelnianie przez reverse proxy.

Weryfikacja

.\.venv\Scripts\python.exe -m pip install -r requirements-dev.txt
.\.venv\Scripts\python.exe -m pytest -q

Testy obejmują rzeczywisty trening wszystkich obszarów, ponowne wczytanie natywnych modeli, HTTP, CSV, izolację przyszłych wartości, pseudonimy, błędy konfiguracji, adapter SQL z kontrolowanym źródłem testowym i dni zmiany czasu. Sprawdzenie na żywej bazie i budowa kontenera wymagają dostępu do bazy oraz działającego Dockera. Wynik wykonanej weryfikacji opisuje VERIFICATION.md.