ultimi fix dashboard

This commit is contained in:
Giuseppe Nucifora 2024-12-18 18:10:16 +01:00
parent 5f58dcf5f5
commit fef5ea645e
2 changed files with 149 additions and 67 deletions

View File

@ -5,10 +5,12 @@ import keras
import joblib
import dash_bootstrap_components as dbc
import os
import argparse
import json
from utils.helpers import clean_column_name
from dashboard.environmental_simulator import *
from dotenv import load_dotenv
from dash import no_update
CONFIG_FILE = 'olive_config.json'
@ -331,6 +333,21 @@ def make_prediction(weather_data, varieties_info, percentages, hectares, simulat
if DEV_MODE:
return mock_make_prediction(weather_data, varieties_info, percentages, hectares, simulation_data)
try:
if MODEL_LOADING:
return {
'olive_production': 0, # kg/ha
'olive_production_total': 0 * hectares, # kg totali
'min_oil_production': 0, # L/ha
'max_oil_production': 0, # L/ha
'avg_oil_production': 0, # L/ha
'avg_oil_production_total': 0 * hectares, # L totali
'water_need': 0, # m³/ha
'water_need_total': 0, # m³ totali
'variety_details': 0,
'hectares': hectares,
'stress_factor': 0 if simulation_data is not None else 1.0
}
print("Inizio della funzione make_prediction")
# Prepara i dati temporali (meteorologici)
@ -443,37 +460,65 @@ def make_prediction(weather_data, varieties_info, percentages, hectares, simulat
# Effettua la predizione
prediction = model.predict(input_data)
print("\nRaw prediction:", prediction)
target_features = [
'olive_prod', # Produzione olive kg/ha
'min_oil_prod', # Produzione minima olio L/ha
'max_oil_prod', # Produzione massima olio L/ha
'avg_oil_prod', # Produzione media olio L/ha
'total_water_need' # Fabbisogno idrico totale m³/ha
]
prediction = scaler_y.inverse_transform(prediction)[0]
print("\nInverse transformed prediction:")
for feature, value in zip(target_features, prediction):
print(f"{feature}: {value:.2f}")
# Applica il fattore di stress se disponibile
if simulation_data is not None:
prediction = prediction * stress_factor
print(f"Applied stress factor: {stress_factor}")
print(f"Prediction after stress:", prediction)
# Calcola i valori per ettaro dividendo per il numero di ettari
olive_prod_ha = prediction[0] / hectares
min_oil_prod_ha = prediction[1] / hectares
max_oil_prod_ha = prediction[2] / hectares
avg_oil_prod_ha = prediction[3] / hectares
water_need_ha = prediction[4] / hectares
print("\nValori per ettaro:")
print(f"Olive production per ha: {olive_prod_ha:.2f} kg/ha")
print(f"Min oil production per ha: {min_oil_prod_ha:.2f} L/ha")
print(f"Max oil production per ha: {max_oil_prod_ha:.2f} L/ha")
print(f"Avg oil production per ha: {avg_oil_prod_ha:.2f} L/ha")
print(f"Water need per ha: {water_need_ha:.2f} m³/ha")
# Calcola i dettagli per varietà
variety_details = []
total_water_need = 0
total_water_need = prediction[4] # Usa il valore predetto totale
for variety_info, percentage in zip(varieties_info, percentages):
# Calcoli specifici per varietà
prod_per_ha = float(variety_info['Produzione (tonnellate/ettaro)']) * 1000 * (percentage / 100)
base_prod_per_ha = float(variety_info['Produzione (tonnellate/ettaro)']) * 1000 * (percentage / 100)
prod_per_ha = base_prod_per_ha
if simulation_data is not None:
prod_per_ha *= stress_factor
prod_total = prod_per_ha * hectares
oil_per_ha = float(variety_info['Produzione Olio (litri/ettaro)']) * (percentage / 100)
base_oil_per_ha = float(variety_info['Produzione Olio (litri/ettaro)']) * (percentage / 100)
oil_per_ha = base_oil_per_ha
if simulation_data is not None:
oil_per_ha *= stress_factor
oil_total = oil_per_ha * hectares
# Calcolo fabbisogno idrico medio
water_need = (
float(variety_info['Fabbisogno Acqua Primavera (m³/ettaro)']) +
float(variety_info['Fabbisogno Acqua Estate (m³/ettaro)']) +
float(variety_info['Fabbisogno Acqua Autunno (m³/ettaro)']) +
float(variety_info['Fabbisogno Acqua Inverno (m³/ettaro)'])
) / 4 * (percentage / 100)
total_water_need += water_need * hectares
print(f"\nVariety: {variety_info['Varietà di Olive']}")
print(f"Base production: {base_prod_per_ha:.2f} kg/ha")
print(f"Final production: {prod_per_ha:.2f} kg/ha")
print(f"Base oil: {base_oil_per_ha:.2f} L/ha")
print(f"Final oil: {oil_per_ha:.2f} L/ha")
variety_details.append({
'variety': variety_info['Varietà di Olive'],
@ -482,19 +527,21 @@ def make_prediction(weather_data, varieties_info, percentages, hectares, simulat
'production_total': prod_total,
'oil_per_ha': oil_per_ha,
'oil_total': oil_total,
'water_need': water_need,
'water_need': water_need_ha * (percentage / 100), # Distribuisci il fabbisogno idrico in base alla percentuale
'base_production': base_prod_per_ha, # Produzione senza stress
'base_oil': base_oil_per_ha, # Produzione olio senza stress
'stress_factor': stress_factor if simulation_data is not None else 1.0
})
return {
'olive_production': prediction[0], # kg/ha
'olive_production_total': prediction[0] * hectares, # kg totali
'min_oil_production': prediction[1], # L/ha
'max_oil_production': prediction[2], # L/ha
'avg_oil_production': prediction[3], # L/ha
'avg_oil_production_total': prediction[3] * hectares, # L totali
'water_need': prediction[4], # m³/ha
'water_need_total': total_water_need, # m³ totali
'olive_production': olive_prod_ha, # kg/ha
'olive_production_total': prediction[0], # kg totali
'min_oil_production': min_oil_prod_ha, # L/ha
'max_oil_production': max_oil_prod_ha, # L/ha
'avg_oil_production': avg_oil_prod_ha, # L/ha
'avg_oil_production_total': prediction[3], # L totali
'water_need': water_need_ha, # m³/ha
'water_need_total': prediction[4], # m³ totali
'variety_details': variety_details,
'hectares': hectares,
'stress_factor': stress_factor if simulation_data is not None else 1.0
@ -872,6 +919,24 @@ def create_configuration_tab():
], label="Configurazione", tab_id="tab-config")
@app.callback(
Output('loading-alert', 'children'),
[Input('simulate-btn', 'n_clicks'),
Input('debug-switch', 'value')]
)
def update_loading_status(n_clicks, debug_mode):
if MODEL_LOADING:
return dbc.Alert(
[
html.I(className="fas fa-spinner fa-spin me-2"),
"Caricamento del modello in corso..."
],
color="warning",
is_open=True
)
return None
@app.callback(
[Output('inference-status', 'children'),
Output('inference-mode', 'children'),
@ -880,8 +945,7 @@ def create_configuration_tab():
[Input('debug-switch', 'value')]
)
def toggle_inference_mode(debug_mode):
global DEV_MODE
global model
global DEV_MODE, model, MODEL_LOADING, scaler_temporal, scaler_static, scaler_y
try:
config = load_config()
@ -899,6 +963,8 @@ def toggle_inference_mode(debug_mode):
DEV_MODE = debug_mode
if debug_mode:
MODEL_LOADING = False
model = None
return (
dbc.Alert("Modalità Debug attiva - Using mock predictions", color="info"),
"Debug (Mock)",
@ -907,6 +973,7 @@ def toggle_inference_mode(debug_mode):
)
else:
try:
MODEL_LOADING = True
print(f"Keras version: {keras.__version__}")
print(f"TensorFlow version: {tf.__version__}")
print(f"CUDA available: {tf.test.is_built_with_cuda()}")
@ -1046,7 +1113,7 @@ def toggle_inference_mode(debug_mode):
'WarmUpLearningRateSchedule': WarmUpLearningRateSchedule,
'weighted_huber_loss': weighted_huber_loss
})
MODEL_LOADING = False
return (
dbc.Alert("Modello caricato correttamente", color="success"),
"Produzione (Local Model)",
@ -1057,15 +1124,7 @@ def toggle_inference_mode(debug_mode):
print(f"Errore nel caricamento del modello: {str(e)}")
# Se c'è un errore nel caricamento del modello, torna in modalità debug
DEV_MODE = True
# Aggiorna la configurazione per riflettere il fallback
config['inference']['debug_mode'] = True
try:
with open(CONFIG_FILE, 'w') as f:
json.dump(config, f, indent=4)
except Exception as save_error:
print(f"Errore nel salvataggio della configurazione di fallback: {save_error}")
MODEL_LOADING = False
return (
dbc.Alert(f"Errore nel caricamento del modello: {str(e)}", color="danger"),
"Debug (Mock) - Fallback",
@ -1074,6 +1133,7 @@ def toggle_inference_mode(debug_mode):
)
except Exception as e:
print(f"Errore nella configurazione inferenza: {str(e)}")
MODEL_LOADING = False
return (
dbc.Alert(f"Errore: {str(e)}", color="danger"),
"Errore",
@ -1846,7 +1906,6 @@ def create_costs_config_section():
def create_inference_config_section():
config = load_config()
debug_mode = config.get('inference', {}).get('debug_mode', True)
@ -1921,6 +1980,7 @@ def create_inference_config_section():
app.layout = dbc.Container([
dcc.Location(id='_pages_location'),
html.Div(id='loading-alert'),
variety2_tooltip,
variety3_tooltip,
# Header
@ -2217,12 +2277,36 @@ def create_figure_layout(fig, title):
return fig
from dash import no_update
@app.callback(
Output("percentage-warning", "children"),
[
# Outputs per i costi e configurazioni base (16 outputs)
Input("percentage-1-input", "value"),
Input("percentage-2-input", "value"),
Input("percentage-3-input", "value")
]
)
def check_percentages(perc1, perc2, perc3):
try:
# Calcola la somma delle percentuali, considerando solo i valori non nulli
total = sum(p for p in [perc1 or 0, perc2 or 0, perc3 or 0])
if total > 100:
return dbc.Alert(
f"La somma delle percentuali è {total}% (non può superare 100%)",
color="danger",
className="mt-2"
)
return ""
except Exception as e:
print(f"Errore nel controllo delle percentuali: {str(e)}")
return ""
@app.callback(
[
# Outputs per i costi e configurazioni base (15 outputs, escluso warning)
Output("hectares-input", "value"),
Output("variety-1-dropdown", "value"),
Output("technique-1-dropdown", "value"),
@ -2238,7 +2322,6 @@ from dash import no_update
Output("technique-3-dropdown", "disabled"),
Output("percentage-3-input", "value"),
Output("percentage-3-input", "disabled"),
Output("percentage-warning", "children"),
# Outputs per i costi fissi (4 outputs)
Output("cost-ammortamento", "value"),
Output("cost-assicurazione", "value"),
@ -2264,18 +2347,12 @@ from dash import no_update
Input("tabs", "active_tab"),
Input("variety-2-dropdown", "value"),
Input("variety-3-dropdown", "value"),
Input("percentage-1-input", "value"),
Input("percentage-2-input", "value"),
Input("percentage-3-input", "value"),
Input('_pages_location', 'pathname') # Aggiunto per trigger all'avvio
Input('_pages_location', 'pathname')
]
)
def unified_config_manager(active_tab, variety2, variety3, perc1, perc2, perc3, pathname):
ctx = callback_context
trigger_id = ctx.triggered[0]['prop_id'].split('.')[0] if ctx.triggered else None
def load_configuration(active_tab, variety2, variety3, pathname):
try:
# Carica sempre la configurazione
# Carica la configurazione
config = load_config()
# Carica dati varietà
@ -2294,14 +2371,8 @@ def unified_config_manager(active_tab, variety2, variety3, perc1, perc2, perc3,
var2_exists = var2["variety"] is not None
var3_exists = var3["variety"] is not None
# Calcolo warning percentuali
total = sum(v["percentage"] for v in varieties if v["variety"] is not None)
warning = ""
if total != 100:
warning = f"La somma delle percentuali è {total}% (dovrebbe essere 100%)"
return [
# Configurazioni base (16 valori)
# Configurazioni base (15 valori)
config['oliveto']['hectares'],
var1["variety"],
var1["technique"],
@ -2317,7 +2388,6 @@ def unified_config_manager(active_tab, variety2, variety3, perc1, perc2, perc3,
not var2_exists or not var3_exists,
var3["percentage"],
not var2_exists or not var3_exists,
warning,
# Costi fissi (4 valori)
fixed.get('ammortamento', 10000),
fixed.get('assicurazione', 2500),
@ -2341,9 +2411,8 @@ def unified_config_manager(active_tab, variety2, variety3, perc1, perc2, perc3,
]
except Exception as e:
print(f"Errore in unified_config_manager: {str(e)}")
# In caso di errore, ritorna no_update per tutti i valori
return [no_update] * 32
print(f"Errore in load_configuration: {str(e)}")
return [no_update] * 31
def create_production_details_figure(prediction):
@ -2505,7 +2574,7 @@ def update_simulation(n_clicks, temp_range, humidity, rainfall, radiation):
"""
Callback principale per aggiornare tutti i componenti della simulazione
"""
if n_clicks is None:
if n_clicks is None or MODEL_LOADING:
# Crea grafici vuoti per l'inizializzazione
empty_growth_fig = go.Figure()
empty_production_fig = go.Figure()
@ -2569,8 +2638,6 @@ def update_simulation(n_clicks, temp_range, humidity, rainfall, radiation):
varieties_info.append(variety_data.iloc[0])
percentages.append(variety_config['percentage'])
print(sim_data)
prediction = make_prediction(weather_data, varieties_info, percentages, hectares, sim_data)
# Formattazione output con valori per ettaro e totali
@ -2692,4 +2759,16 @@ def update_graph_style(graph_id):
if __name__ == '__main__':
app.run_server(debug=True)
port = int(os.environ.get('DASH_PORT', 8050))
debug = int(os.environ.get('DASH_DEBUG', True))
# Oppure usando argparse per gli argomenti da riga di comando
parser = argparse.ArgumentParser()
parser.add_argument('--port', type=int, default=8050, help='Port to run the server on')
args = parser.parse_args()
app.run_server(
host='0.0.0.0',
port=args.port,
debug=debug
)

View File

@ -1,20 +1,20 @@
{
"oliveto": {
"hectares": 10,
"hectares": 4.35,
"varieties": [
{
"variety": "Nocellara dell'Etna",
"technique": "intensiva",
"percentage": 30
"technique": "tradizionale",
"percentage": 50
},
{
"variety": "Frantoio",
"technique": "tradizionale",
"percentage": 30
"percentage": 10
},
{
"variety": "Coratina",
"technique": "superintensiva",
"technique": "tradizionale",
"percentage": 40
}
]
@ -44,5 +44,8 @@
"prezzo_vendita": 12,
"perc_vendita_diretta": 30
}
},
"inference": {
"debug_mode": false
}
}