Kubas126cz commited on
Commit
2bad250
·
verified ·
1 Parent(s): ff4c899
.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