Spaces:
Sleeping
Sleeping
jha_init
Browse files- .gitattributes +1 -0
- input_preprocessor_meteo_to_smape25.pkl +3 -0
- main.py +51 -0
- meteo_functions.py +142 -0
- output_predictions_to_meteo_smape_25.keras +3 -0
- output_scaler_meteo_to_smape25.pkl +3 -0
- predictions.py +60 -0
- preprocessing_functions.py +105 -0
- requirements.txt +9 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
output_predictions_to_meteo_smape_25.keras filter=lfs diff=lfs merge=lfs -text
|
input_preprocessor_meteo_to_smape25.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1746e606af1ecd0e65af7f542d9d9153e285ea6d31aa4965f318b402a3c691f2
|
| 3 |
+
size 5676
|
main.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
from datetime import timedelta
|
| 5 |
+
import datetime
|
| 6 |
+
from meteo_functions import get_meteo_data, get_air_quality_data, get_forecast_meteo_data, get_air_quality_forecast
|
| 7 |
+
from predictions import predict
|
| 8 |
+
import gc
|
| 9 |
+
|
| 10 |
+
def clear_memory():
|
| 11 |
+
gc.collect()
|
| 12 |
+
|
| 13 |
+
st.title("Predikce výkonu FVE ABA")
|
| 14 |
+
#t.header("this is a header")
|
| 15 |
+
#sst.subheader("subheader")
|
| 16 |
+
#st.markdown("This is **Markdown**")
|
| 17 |
+
#st.caption("small text")
|
| 18 |
+
|
| 19 |
+
today = datetime.date.today()
|
| 20 |
+
max_date = today + datetime.timedelta(days=4)
|
| 21 |
+
|
| 22 |
+
with st.form(key="sample_form"):
|
| 23 |
+
date_utc = st.date_input("Vyber den", max_value=max_date)
|
| 24 |
+
submit_button = st.form_submit_button(label="Predikuj")
|
| 25 |
+
|
| 26 |
+
if submit_button:
|
| 27 |
+
previous_day = date_utc - timedelta(days=1)
|
| 28 |
+
if date_utc < today - datetime.timedelta(days=1):
|
| 29 |
+
# st.subheader(f"Predikce výkonu pro: {date_utc}:")
|
| 30 |
+
|
| 31 |
+
df_meteo = get_meteo_data(previous_day, date_utc)
|
| 32 |
+
df_air_quality = get_air_quality_data(previous_day, date_utc)
|
| 33 |
+
|
| 34 |
+
data = df_meteo.merge(df_air_quality, on="DT", how="inner")
|
| 35 |
+
predict(data)
|
| 36 |
+
clear_memory()
|
| 37 |
+
|
| 38 |
+
elif previous_day < date_utc <= today + datetime.timedelta(days=4):
|
| 39 |
+
# st.header(f"Data pro: {date_utc}:")
|
| 40 |
+
df_meteo = get_forecast_meteo_data(previous_day, date_utc)
|
| 41 |
+
df_air_quality = get_air_quality_forecast(previous_day, date_utc)
|
| 42 |
+
data = df_meteo.merge(df_air_quality, on="DT", how="inner")
|
| 43 |
+
#st.write("Budouci data:")
|
| 44 |
+
#st.dataframe(df_meteo)
|
| 45 |
+
#st.dataframe(df_air_quality)
|
| 46 |
+
#st.dataframe(data)
|
| 47 |
+
predict(data)
|
| 48 |
+
clear_memory()
|
| 49 |
+
|
| 50 |
+
else:
|
| 51 |
+
st.warning("Predikce je dostupná pouze pro následujících 5 dnů.")
|
meteo_functions.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import requests
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
lat = 49.13114
|
| 7 |
+
lon = 15.18067
|
| 8 |
+
|
| 9 |
+
def get_meteo_data(start_date, end_date):
|
| 10 |
+
url = f"https://archive-api.open-meteo.com/v1/archive?latitude={lat}&longitude={lon}&start_date={start_date}&end_date={end_date}&hourly=temperature_2m,relative_humidity_2m,surface_pressure,cloudcover,windspeed_10m,wind_direction_10m,direct_normal_irradiance,diffuse_radiation,shortwave_radiation&timezone=UTC"
|
| 11 |
+
|
| 12 |
+
response = requests.get(url)
|
| 13 |
+
if response.status_code == 200:
|
| 14 |
+
weather_data = response.json()
|
| 15 |
+
|
| 16 |
+
if "hourly" in weather_data:
|
| 17 |
+
df_weather = pd.DataFrame({
|
| 18 |
+
"DT": pd.to_datetime(weather_data["hourly"]["time"]),
|
| 19 |
+
"Temperature_2m": weather_data["hourly"].get("temperature_2m", []),
|
| 20 |
+
"Relative_Humidity_2m": weather_data["hourly"].get("relative_humidity_2m", []),
|
| 21 |
+
"Surface_Pressure": weather_data["hourly"].get("surface_pressure", []),
|
| 22 |
+
"Cloud_Cover": weather_data["hourly"].get("cloudcover", []),
|
| 23 |
+
"Wind_Speed_10m": weather_data["hourly"].get("windspeed_10m", []),
|
| 24 |
+
"Wind_Direction_10m": weather_data["hourly"].get("wind_direction_10m", []),
|
| 25 |
+
"RAD": weather_data["hourly"].get("shortwave_radiation", [])
|
| 26 |
+
})
|
| 27 |
+
|
| 28 |
+
df_weather["DT"] = df_weather["DT"].dt.tz_localize(None)
|
| 29 |
+
|
| 30 |
+
df_weather["wind_u"] = df_weather["Wind_Speed_10m"] * np.sin(np.radians(df_weather["Wind_Direction_10m"]))
|
| 31 |
+
df_weather["wind_v"] = df_weather["Wind_Speed_10m"] * np.cos(np.radians(df_weather["Wind_Direction_10m"]))
|
| 32 |
+
|
| 33 |
+
df_weather.drop(columns=["Wind_Speed_10m", "Wind_Direction_10m"], inplace=True)
|
| 34 |
+
else:
|
| 35 |
+
print("Chyba: Odpověď neobsahuje klíč 'hourly'.")
|
| 36 |
+
|
| 37 |
+
else:
|
| 38 |
+
print(f"Chyba při stahování dat: {response.status_code}, odpověď: {response.text}")
|
| 39 |
+
|
| 40 |
+
return df_weather
|
| 41 |
+
|
| 42 |
+
def get_air_quality_data(start_date, end_date):
|
| 43 |
+
|
| 44 |
+
url = f"https://air-quality-api.open-meteo.com/v1/air-quality?latitude={lat}&longitude={lon}&start_date={start_date}&end_date={end_date}&hourly=pm10,ozone&timezone=UTC"
|
| 45 |
+
|
| 46 |
+
response = requests.get(url)
|
| 47 |
+
if response.status_code == 200:
|
| 48 |
+
air_quality_data = response.json()
|
| 49 |
+
|
| 50 |
+
if "hourly" in air_quality_data:
|
| 51 |
+
df_air_quality = pd.DataFrame({
|
| 52 |
+
"DT": pd.to_datetime(air_quality_data["hourly"]["time"]),
|
| 53 |
+
"PM10": air_quality_data["hourly"].get("pm10", []),
|
| 54 |
+
"Ozone": air_quality_data["hourly"].get("ozone", [])
|
| 55 |
+
})
|
| 56 |
+
df_air_quality["DT"] = df_air_quality["DT"].dt.tz_localize(None)
|
| 57 |
+
else:
|
| 58 |
+
print("Chyba: Odpověď neobsahuje klíč 'hourly'.")
|
| 59 |
+
else:
|
| 60 |
+
print(f"Chyba při stahování dat: {response.status_code}, odpověď: {response.text}")
|
| 61 |
+
|
| 62 |
+
return df_air_quality
|
| 63 |
+
|
| 64 |
+
def create_time_cycles(weather_dataset):
|
| 65 |
+
weather_dataset["hour"] = weather_dataset["DT"].dt.hour
|
| 66 |
+
weather_dataset["day_of_year"] = weather_dataset["DT"].dt.dayofyear
|
| 67 |
+
weather_dataset["sin_hour"] = np.sin(2 * np.pi * weather_dataset["hour"] / 24)
|
| 68 |
+
weather_dataset["cos_hour"] = np.cos(2 * np.pi * weather_dataset["hour"] / 24)
|
| 69 |
+
weather_dataset["sin_day_of_year"] = np.sin(2 * np.pi * weather_dataset["day_of_year"] / 365)
|
| 70 |
+
weather_dataset["cos_day_of_year"] = np.cos(2 * np.pi * weather_dataset["day_of_year"] / 365)
|
| 71 |
+
weather_dataset.drop(columns=["hour", "day_of_year"], inplace=True)
|
| 72 |
+
return weather_dataset
|
| 73 |
+
|
| 74 |
+
def get_forecast_meteo_data(start_date, end_date):
|
| 75 |
+
url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}&start_date={start_date}&end_date={end_date}&hourly=temperature_2m,relative_humidity_2m,surface_pressure,cloudcover,windspeed_10m,wind_direction_10m,direct_normal_irradiance,diffuse_radiation,shortwave_radiation&timezone=UTC"
|
| 76 |
+
|
| 77 |
+
# Odeslání požadavku
|
| 78 |
+
response = requests.get(url)
|
| 79 |
+
if response.status_code == 200:
|
| 80 |
+
weather_data = response.json()
|
| 81 |
+
|
| 82 |
+
if "hourly" in weather_data:
|
| 83 |
+
df_weather = pd.DataFrame({
|
| 84 |
+
"DT": pd.to_datetime(weather_data["hourly"]["time"]),
|
| 85 |
+
"Temperature_2m": weather_data["hourly"].get("temperature_2m", []),
|
| 86 |
+
"Relative_Humidity_2m": weather_data["hourly"].get("relative_humidity_2m", []),
|
| 87 |
+
"Surface_Pressure": weather_data["hourly"].get("surface_pressure", []),
|
| 88 |
+
"Cloud_Cover": weather_data["hourly"].get("cloudcover", []),
|
| 89 |
+
"Wind_Speed_10m": weather_data["hourly"].get("windspeed_10m", []),
|
| 90 |
+
"Wind_Direction_10m": weather_data["hourly"].get("wind_direction_10m", []),
|
| 91 |
+
"RAD": weather_data["hourly"].get("shortwave_radiation", [])
|
| 92 |
+
})
|
| 93 |
+
|
| 94 |
+
df_weather["DT"] = df_weather["DT"].dt.tz_localize(None)
|
| 95 |
+
|
| 96 |
+
df_weather["wind_u"] = df_weather["Wind_Speed_10m"] * np.sin(np.radians(df_weather["Wind_Direction_10m"]))
|
| 97 |
+
df_weather["wind_v"] = df_weather["Wind_Speed_10m"] * np.cos(np.radians(df_weather["Wind_Direction_10m"]))
|
| 98 |
+
|
| 99 |
+
df_weather.drop(columns=["Wind_Speed_10m", "Wind_Direction_10m"], inplace=True)
|
| 100 |
+
else:
|
| 101 |
+
print("Chyba: Odpověď neobsahuje klíč 'hourly'.")
|
| 102 |
+
else:
|
| 103 |
+
print(f"Chyba při stahování dat: {response.status_code}, odpověď: {response.text}")
|
| 104 |
+
|
| 105 |
+
return df_weather
|
| 106 |
+
|
| 107 |
+
def get_air_quality_forecast(start_date, end_date):
|
| 108 |
+
url = f"https://air-quality-api.open-meteo.com/v1/air-quality?latitude={lat}&longitude={lon}&start_date={start_date}&end_date={end_date}&hourly=pm10,ozone&timezone=UTC"
|
| 109 |
+
|
| 110 |
+
response = requests.get(url)
|
| 111 |
+
if response.status_code == 200:
|
| 112 |
+
air_quality_data = response.json()
|
| 113 |
+
|
| 114 |
+
if "hourly" in air_quality_data:
|
| 115 |
+
times = air_quality_data["hourly"].get("time", [])
|
| 116 |
+
pm10 = air_quality_data["hourly"].get("pm10", [])
|
| 117 |
+
ozone = air_quality_data["hourly"].get("ozone", [])
|
| 118 |
+
|
| 119 |
+
if len(times) == len(pm10) == len(ozone):
|
| 120 |
+
df_air_quality = pd.DataFrame({
|
| 121 |
+
"DT": pd.to_datetime(times),
|
| 122 |
+
"PM10": pm10,
|
| 123 |
+
"Ozone": ozone
|
| 124 |
+
})
|
| 125 |
+
df_air_quality["DT"] = df_air_quality["DT"].dt.tz_localize(None)
|
| 126 |
+
else:
|
| 127 |
+
print("Chyba: Pola mají různé délky!")
|
| 128 |
+
print(f"Počet časových údajů: {len(times)}, Počet PM10: {len(pm10)}, Počet Ozone: {len(ozone)}")
|
| 129 |
+
df_air_quality = pd.DataFrame()
|
| 130 |
+
else:
|
| 131 |
+
print("Chyba: Odpověď neobsahuje klíč 'hourly'.")
|
| 132 |
+
df_air_quality = pd.DataFrame()
|
| 133 |
+
else:
|
| 134 |
+
print(f"Chyba při stahování dat: {response.status_code}, odpověď: {response.text}")
|
| 135 |
+
df_air_quality = pd.DataFrame()
|
| 136 |
+
|
| 137 |
+
return df_air_quality
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
|
output_predictions_to_meteo_smape_25.keras
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:583cbd035b5a57666e362f79581cffd6f15f607bfc20ac57af24d21e6d5adab3
|
| 3 |
+
size 394648365
|
output_scaler_meteo_to_smape25.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a21576128cba609962c3396a6e7397f4a2765ede43a3e4c89d7481b6269ed1e5
|
| 3 |
+
size 1705
|
predictions.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
from meteo_functions import create_time_cycles
|
| 5 |
+
import joblib
|
| 6 |
+
from preprocessing_functions import create_sequences, plot_solar_power_prediction, load_model, load_transformers
|
| 7 |
+
from tensorflow import keras
|
| 8 |
+
import gc
|
| 9 |
+
|
| 10 |
+
def predict(data):
|
| 11 |
+
data = create_time_cycles(data)
|
| 12 |
+
st.divider()
|
| 13 |
+
|
| 14 |
+
# Načtění transformátorů
|
| 15 |
+
input_preprocessor, output_scaler = load_transformers()
|
| 16 |
+
|
| 17 |
+
# transformace vstupnich prom
|
| 18 |
+
X_dataset = input_preprocessor.transform(data)
|
| 19 |
+
X_dataset = pd.DataFrame(X_dataset, columns=input_preprocessor.get_feature_names_out(), index=data.index)
|
| 20 |
+
|
| 21 |
+
rename_map = {
|
| 22 |
+
"yeo_minmax__RAD": "RAD",
|
| 23 |
+
"yeo_minmax__Relative_Humidity_2m": "Relative_Humidity_2m",
|
| 24 |
+
"yeo_minmax__PM10": "PM10",
|
| 25 |
+
"yeo_standard__Cloud_Cover": "Cloud_Cover",
|
| 26 |
+
"minmax__Temperature_2m": "Temperature_2m",
|
| 27 |
+
"minmax__wind_u": "wind_u",
|
| 28 |
+
"minmax__wind_v": "wind_v",
|
| 29 |
+
"minmax__Surface_Pressure": "Surface_Pressure",
|
| 30 |
+
"minmax__Ozone": "Ozone",
|
| 31 |
+
"remainder__sin_hour": "sin_hour",
|
| 32 |
+
"remainder__cos_hour": "cos_hour",
|
| 33 |
+
"remainder__sin_day_of_year": "sin_day_of_year",
|
| 34 |
+
"remainder__cos_day_of_year": "cos_day_of_year"
|
| 35 |
+
}
|
| 36 |
+
X_dataset = X_dataset.rename(columns=rename_map)
|
| 37 |
+
|
| 38 |
+
features = ["RAD", "Relative_Humidity_2m", "Surface_Pressure", 'Cloud_Cover', "Temperature_2m",
|
| 39 |
+
'sin_hour', 'cos_hour', 'cos_day_of_year', "sin_day_of_year", "wind_u", "wind_v", "Ozone", "PM10"]
|
| 40 |
+
|
| 41 |
+
x = create_sequences(X_dataset, window=24, horizon=24, past_features=features, future_features=features)
|
| 42 |
+
|
| 43 |
+
model = load_model()
|
| 44 |
+
|
| 45 |
+
y_pred = model.predict(x) # predikce
|
| 46 |
+
|
| 47 |
+
y_pred_trans = np.array([output_scaler.inverse_transform(y_pred[:, i].reshape(-1, 1)).flatten() for i in range(y_pred.shape[1])]).T
|
| 48 |
+
|
| 49 |
+
y_pred_trans[y_pred_trans < 1] = 0
|
| 50 |
+
st.write("**Predikované hodnoty výkonu (kW) pro jednotlivé hodiny:**")
|
| 51 |
+
st.write(y_pred_trans, use_container_width=True)
|
| 52 |
+
|
| 53 |
+
my_plt = plot_solar_power_prediction(y_pred_trans)
|
| 54 |
+
st.pyplot(my_plt)
|
| 55 |
+
|
| 56 |
+
del x, y_pred, y_pred_trans
|
| 57 |
+
keras.backend.clear_session() # Uvolnění TensorFlow session
|
| 58 |
+
gc.collect()
|
| 59 |
+
|
| 60 |
+
return None
|
preprocessing_functions.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import tensorflow as tf
|
| 3 |
+
import streamlit as st
|
| 4 |
+
import os
|
| 5 |
+
import requests
|
| 6 |
+
import matplotlib.pyplot as plt
|
| 7 |
+
import joblib
|
| 8 |
+
|
| 9 |
+
MODEL_URL = "https://github.com/Kuba129cz/FVE_ABA/releases/download/model_FVE/output_predictions_to_meteo_smape_25.keras"
|
| 10 |
+
MODEL_PATH = "model.keras"
|
| 11 |
+
|
| 12 |
+
def download_model():
|
| 13 |
+
if not os.path.exists(MODEL_PATH):
|
| 14 |
+
st.info("Stahuji model, prosím čekejte...")
|
| 15 |
+
response = requests.get(MODEL_URL, stream=True)
|
| 16 |
+
|
| 17 |
+
if response.status_code == 200:
|
| 18 |
+
with open(MODEL_PATH, "wb") as f:
|
| 19 |
+
for chunk in response.iter_content(chunk_size=8192):
|
| 20 |
+
f.write(chunk)
|
| 21 |
+
st.success("Model byl úspěšně stažen.")
|
| 22 |
+
else:
|
| 23 |
+
st.error("Nepodařilo se stáhnout model. Zkontrolujte URL.")
|
| 24 |
+
else:
|
| 25 |
+
st.info("Model již je stažen.")
|
| 26 |
+
|
| 27 |
+
@st.cache_resource
|
| 28 |
+
def load_model():
|
| 29 |
+
download_model()
|
| 30 |
+
model = tf.keras.models.load_model(MODEL_PATH)
|
| 31 |
+
return model
|
| 32 |
+
|
| 33 |
+
@st.cache_resource
|
| 34 |
+
def load_transformers():
|
| 35 |
+
input_preprocessor = joblib.load('input_preprocessor_meteo_to_smape25.pkl')
|
| 36 |
+
output_scaler = joblib.load('output_scaler_meteo_to_smape25.pkl')
|
| 37 |
+
|
| 38 |
+
return input_preprocessor, output_scaler
|
| 39 |
+
|
| 40 |
+
def create_sequences(data, window, horizon, past_features, future_features):
|
| 41 |
+
"""
|
| 42 |
+
Vytvoří sekvence vstupních dat a odpovídající cílové hodnoty pro trénování LSTM modelu.
|
| 43 |
+
|
| 44 |
+
Parametry:
|
| 45 |
+
----------
|
| 46 |
+
data : pandas.DataFrame
|
| 47 |
+
DataFrame obsahující časové řady.
|
| 48 |
+
window : int
|
| 49 |
+
Počet časových kroků v minulosti.
|
| 50 |
+
horizon : int
|
| 51 |
+
Počet časových kroků do budoucnosti.
|
| 52 |
+
past_features : list
|
| 53 |
+
Seznam sloupců, které budou použity jako vstupní vlastnosti v minulosti.
|
| 54 |
+
future_features : list
|
| 55 |
+
Seznam sloupců, které budou použity jako vstupní vlastnosti v budoucnosti.
|
| 56 |
+
target : str
|
| 57 |
+
Název sloupce, který bude použit jako cílová hodnota.
|
| 58 |
+
|
| 59 |
+
Návratové hodnoty:
|
| 60 |
+
-------------------
|
| 61 |
+
X : numpy.ndarray
|
| 62 |
+
Pole tvaru (vzorky, window, past_features + future_features), obsahující sekvence vstupních dat.
|
| 63 |
+
y : numpy.ndarray
|
| 64 |
+
Pole tvaru (vzorky, horizon), obsahující odpovídající cílové hodnoty.
|
| 65 |
+
"""
|
| 66 |
+
|
| 67 |
+
X_past = np.lib.stride_tricks.sliding_window_view(
|
| 68 |
+
data[past_features].values, (window, len(past_features))
|
| 69 |
+
)[:-horizon, :, :]
|
| 70 |
+
|
| 71 |
+
X_past = np.squeeze(X_past, axis=1)
|
| 72 |
+
|
| 73 |
+
X_future = np.lib.stride_tricks.sliding_window_view(
|
| 74 |
+
data[future_features].values, (window, len(future_features))
|
| 75 |
+
)[horizon-1 : len(X_past) + horizon-1, :, :]
|
| 76 |
+
|
| 77 |
+
X_future = np.squeeze(X_future, axis=1)
|
| 78 |
+
|
| 79 |
+
X = np.concatenate([X_past, X_future], axis=2)
|
| 80 |
+
|
| 81 |
+
return X
|
| 82 |
+
|
| 83 |
+
def plot_solar_power_prediction(y_pred_trans):
|
| 84 |
+
"""
|
| 85 |
+
Vytvoří graf predikce výkonu fotovoltaické elektrárny v průběhu dne.
|
| 86 |
+
|
| 87 |
+
Args:
|
| 88 |
+
y_pred_trans (numpy.ndarray): Pole s predikovanými hodnotami výkonu (kW) ve tvaru (1, 24).
|
| 89 |
+
|
| 90 |
+
Returns:
|
| 91 |
+
plt.Figure: Graf pro zobrazení.
|
| 92 |
+
"""
|
| 93 |
+
hours = np.arange(24)
|
| 94 |
+
|
| 95 |
+
plt.figure(figsize=(10, 6))
|
| 96 |
+
plt.plot(hours, y_pred_trans.flatten(), marker='o', label='Výkon (kW)')
|
| 97 |
+
plt.xlabel('Hodiny')
|
| 98 |
+
plt.ylabel('Výkon (kW)')
|
| 99 |
+
plt.title('Predikce výkonu fotovoltaické elektrárny v průběhu dne')
|
| 100 |
+
plt.xticks(hours)
|
| 101 |
+
plt.grid(True)
|
| 102 |
+
plt.legend()
|
| 103 |
+
|
| 104 |
+
return plt
|
| 105 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit
|
| 2 |
+
pandas
|
| 3 |
+
numpy
|
| 4 |
+
matplotlib
|
| 5 |
+
tensorflow
|
| 6 |
+
joblib
|
| 7 |
+
requests
|
| 8 |
+
scipy
|
| 9 |
+
scikit-learn
|