Compare commits
No commits in common. "master" and "feature/dashboard" have entirely different histories.
master
...
feature/da
14
.idea/csv-editor.xml
generated
14
.idea/csv-editor.xml
generated
@ -17,20 +17,6 @@
|
|||||||
</Attribute>
|
</Attribute>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
<entry key="/dumpDataPreview">
|
|
||||||
<value>
|
|
||||||
<Attribute>
|
|
||||||
<option name="separator" value="," />
|
|
||||||
</Attribute>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
<entry key="/textView">
|
|
||||||
<value>
|
|
||||||
<Attribute>
|
|
||||||
<option name="separator" value="," />
|
|
||||||
</Attribute>
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
124
README.md
124
README.md
@ -1,124 +0,0 @@
|
|||||||
# Dashboard Produzione Olio d'Oliva
|
|
||||||
|
|
||||||
Questa dashboard interattiva permette di simulare e analizzare la produzione di olio d'oliva basandosi su diversi parametri ambientali e varietali.
|
|
||||||
|
|
||||||
## Requisiti di Sistema
|
|
||||||
|
|
||||||
- Python 3.8 o superiore
|
|
||||||
- Git LFS (per i file di grandi dimensioni)
|
|
||||||
- Conda (consigliato) o pip
|
|
||||||
|
|
||||||
## Configurazione dell'Ambiente
|
|
||||||
|
|
||||||
### Utilizzando Conda (Consigliato)
|
|
||||||
|
|
||||||
1. Clona il repository:
|
|
||||||
2. Crea e attiva l'ambiente conda:
|
|
||||||
```bash
|
|
||||||
conda env create -f src/environment.yml
|
|
||||||
conda activate olive-dashboard
|
|
||||||
```
|
|
||||||
|
|
||||||
### Utilizzando pip
|
|
||||||
|
|
||||||
1. Clona il repository:
|
|
||||||
2. Crea e attiva un ambiente virtuale:
|
|
||||||
```bash
|
|
||||||
python -m venv venv
|
|
||||||
source venv/bin/activate # Linux/MacOS
|
|
||||||
# oppure
|
|
||||||
.\venv\Scripts\activate # Windows
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Installa le dipendenze:
|
|
||||||
```bash
|
|
||||||
pip install -r src/requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
## Esecuzione della Dashboard
|
|
||||||
|
|
||||||
1. Assicurati di essere nella directory `src`:
|
|
||||||
```bash
|
|
||||||
cd src
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Avvia la dashboard:
|
|
||||||
```bash
|
|
||||||
python olive-oil-dashboard.py [options]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Opzioni disponibili:
|
|
||||||
|
|
||||||
- port PORT: Specifica la porta su cui avviare il server (default: 8888)
|
|
||||||
- debug : Attiva la modalità debug con auto-reload (default: False)
|
|
||||||
|
|
||||||
#### Esempio:
|
|
||||||
```bash
|
|
||||||
python olive-oil-dashboard.py --port 8888 --debug
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Apri un browser e vai all'indirizzo:
|
|
||||||
```
|
|
||||||
http://localhost:8888
|
|
||||||
```
|
|
||||||
|
|
||||||
## Struttura del Progetto
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
├── dashboard/ # Componenti della dashboard
|
|
||||||
├── sources/ # Dati e modelli
|
|
||||||
├── utils/ # Utility functions
|
|
||||||
├── olive-oil-dashboard.py # Main application
|
|
||||||
├── olive_config.json # Configuration file
|
|
||||||
└── requirements.txt # Python dependencies
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funzionalità Principali
|
|
||||||
|
|
||||||
La dashboard offre diverse funzionalità:
|
|
||||||
|
|
||||||
1. **Configurazione Oliveto**
|
|
||||||
- Gestione delle varietà di olive
|
|
||||||
- Configurazione delle tecniche di coltivazione
|
|
||||||
- Impostazione delle percentuali di mix varietale
|
|
||||||
|
|
||||||
2. **Simulazione Ambientale**
|
|
||||||
- Simulazione degli effetti delle condizioni meteorologiche
|
|
||||||
- Analisi dell'impatto sulla produzione
|
|
||||||
- Visualizzazione KPI
|
|
||||||
|
|
||||||
3. **Analisi Economica**
|
|
||||||
- Gestione dei costi di produzione
|
|
||||||
- Analisi dei margini
|
|
||||||
- Proiezioni finanziarie
|
|
||||||
|
|
||||||
4. **Produzione**
|
|
||||||
- Monitoraggio della produzione
|
|
||||||
- Analisi del fabbisogno idrico
|
|
||||||
- Dettagli per varietà
|
|
||||||
|
|
||||||
## Risoluzione Problemi Comuni
|
|
||||||
|
|
||||||
### ModuleNotFoundError
|
|
||||||
|
|
||||||
Se riscontri errori del tipo "ModuleNotFoundError", verifica di:
|
|
||||||
|
|
||||||
1. Aver attivato l'ambiente virtuale corretto
|
|
||||||
2. Aver installato tutte le dipendenze:
|
|
||||||
```bash
|
|
||||||
pip install -r requirements.txt # se usi pip
|
|
||||||
# oppure
|
|
||||||
conda env update -f environment.yml # se usi conda
|
|
||||||
```
|
|
||||||
|
|
||||||
### Errori di Importazione dei Modelli
|
|
||||||
|
|
||||||
Se riscontri errori nell'importazione dei modelli:
|
|
||||||
|
|
||||||
1. Verifica che `DEV_MODE=True` nel file `.env`
|
|
||||||
2. Controlla che tutti i file necessari siano presenti nella directory `sources/`
|
|
||||||
|
|
||||||
## Supporto
|
|
||||||
|
|
||||||
Per problemi o domande, aprire una issue nel repository del progetto.
|
|
||||||
14
src/.gitignore
vendored
14
src/.gitignore
vendored
@ -1,15 +1 @@
|
|||||||
/sources
|
/sources
|
||||||
|
|
||||||
|
|
||||||
/auth/config/users/*.json
|
|
||||||
users/*.json
|
|
||||||
# Python cache files
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.idea/
|
|
||||||
.vscode/
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
@ -35,6 +35,13 @@ Questa dashboard interattiva permette di simulare e analizzare la produzione di
|
|||||||
pip install -r src/requirements.txt
|
pip install -r src/requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Configurazione del Progetto
|
||||||
|
|
||||||
|
1. Crea un file `.env` nella directory `src` con le seguenti variabili:
|
||||||
|
```env
|
||||||
|
DEV_MODE=True # Imposta su False per utilizzare i modelli ML
|
||||||
|
```
|
||||||
|
|
||||||
## Esecuzione della Dashboard
|
## Esecuzione della Dashboard
|
||||||
|
|
||||||
1. Assicurati di essere nella directory `src`:
|
1. Assicurati di essere nella directory `src`:
|
||||||
@ -44,22 +51,12 @@ Questa dashboard interattiva permette di simulare e analizzare la produzione di
|
|||||||
|
|
||||||
2. Avvia la dashboard:
|
2. Avvia la dashboard:
|
||||||
```bash
|
```bash
|
||||||
python olive-oil-dashboard.py [options]
|
python olive-oil-dashboard.py
|
||||||
```
|
|
||||||
|
|
||||||
#### Opzioni disponibili:
|
|
||||||
|
|
||||||
- port PORT: Specifica la porta su cui avviare il server (default: 8888)
|
|
||||||
- debug : Attiva la modalità debug con auto-reload (default: False)
|
|
||||||
|
|
||||||
#### Esempio:
|
|
||||||
```bash
|
|
||||||
python olive-oil-dashboard.py --port 8888 --debug
|
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Apri un browser e vai all'indirizzo:
|
3. Apri un browser e vai all'indirizzo:
|
||||||
```
|
```
|
||||||
http://localhost:8888
|
http://localhost:8050
|
||||||
```
|
```
|
||||||
|
|
||||||
## Struttura del Progetto
|
## Struttura del Progetto
|
||||||
|
|||||||
BIN
src/__pycache__/__init__.cpython-39.pyc
Executable file
BIN
src/__pycache__/__init__.cpython-39.pyc
Executable file
Binary file not shown.
@ -1,91 +0,0 @@
|
|||||||
import dash_bootstrap_components as dbc
|
|
||||||
from dash import html, dcc
|
|
||||||
|
|
||||||
from components.ids import Ids
|
|
||||||
|
|
||||||
def create_login_layout():
|
|
||||||
return dbc.Container([
|
|
||||||
dbc.Row([
|
|
||||||
dbc.Col([
|
|
||||||
html.H2("Login Dashboard Olio d'Oliva", className="text-center mb-4"),
|
|
||||||
dbc.Card([
|
|
||||||
dbc.CardBody([
|
|
||||||
dbc.Input(
|
|
||||||
id=Ids.LOGIN_USERNAME,
|
|
||||||
type="text",
|
|
||||||
placeholder="Username",
|
|
||||||
className="mb-3"
|
|
||||||
),
|
|
||||||
dbc.Input(
|
|
||||||
id=Ids.LOGIN_PASSWORD,
|
|
||||||
type="password",
|
|
||||||
placeholder="Password",
|
|
||||||
className="mb-3"
|
|
||||||
),
|
|
||||||
dbc.Button(
|
|
||||||
"Login",
|
|
||||||
id=Ids.LOGIN_BUTTON,
|
|
||||||
color="primary",
|
|
||||||
className="w-100 mb-3"
|
|
||||||
),
|
|
||||||
html.Div(id=Ids.LOGIN_ERROR),
|
|
||||||
html.Hr(),
|
|
||||||
html.P("Non hai un account?", className="text-center"),
|
|
||||||
dbc.Button(
|
|
||||||
"Registrati",
|
|
||||||
id=Ids.SHOW_REGISTER_BUTTON,
|
|
||||||
color="secondary",
|
|
||||||
className="w-100"
|
|
||||||
)
|
|
||||||
])
|
|
||||||
])
|
|
||||||
], md=6, className="mx-auto")
|
|
||||||
], className="vh-100 align-items-center")
|
|
||||||
])
|
|
||||||
|
|
||||||
def create_register_layout():
|
|
||||||
return dbc.Container([
|
|
||||||
dbc.Row([
|
|
||||||
dbc.Col([
|
|
||||||
html.H2("Registrazione", className="text-center mb-4"),
|
|
||||||
dbc.Card([
|
|
||||||
dbc.CardBody([
|
|
||||||
dbc.Input(
|
|
||||||
id=Ids.REGISTER_USERNAME,
|
|
||||||
type="text",
|
|
||||||
placeholder="Username",
|
|
||||||
className="mb-3"
|
|
||||||
),
|
|
||||||
dbc.Input(
|
|
||||||
id=Ids.REGISTER_PASSWORD,
|
|
||||||
type="password",
|
|
||||||
placeholder="Password",
|
|
||||||
className="mb-3"
|
|
||||||
),
|
|
||||||
dbc.Input(
|
|
||||||
id=Ids.REGISTER_CONFIRM,
|
|
||||||
type="password",
|
|
||||||
placeholder="Conferma Password",
|
|
||||||
className="mb-3"
|
|
||||||
),
|
|
||||||
dbc.Button(
|
|
||||||
"Registrati",
|
|
||||||
id=Ids.REGISTER_BUTTON,
|
|
||||||
color="primary",
|
|
||||||
className="w-100 mb-3"
|
|
||||||
),
|
|
||||||
html.Div(id=Ids.REGISTER_ERROR),
|
|
||||||
html.Div(id=Ids.REGISTER_SUCCESS),
|
|
||||||
html.Hr(),
|
|
||||||
html.P("Hai già un account?", className="text-center"),
|
|
||||||
dbc.Button(
|
|
||||||
"Torna al Login",
|
|
||||||
id=Ids.SHOW_LOGIN_BUTTON,
|
|
||||||
color="secondary",
|
|
||||||
className="w-100"
|
|
||||||
)
|
|
||||||
])
|
|
||||||
])
|
|
||||||
], md=6, className="mx-auto")
|
|
||||||
], className="vh-100 align-items-center")
|
|
||||||
])
|
|
||||||
@ -1,236 +0,0 @@
|
|||||||
import json
|
|
||||||
import os
|
|
||||||
import hashlib
|
|
||||||
import jwt as pyjwt
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import secrets
|
|
||||||
|
|
||||||
# Costanti
|
|
||||||
SECRET_KEY = 'M!3EmyJ@P$yqt$dYRQ#73QtxFy$aTn8M98P8i5T9x9Fd5LHMcHgdfEEt#?H9EPg&9Qhokh$#pTyYLHxL' # In produzione, usare una variabile d'ambiente
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
USERS_FILE = os.path.join(BASE_DIR, "users", "users.json")
|
|
||||||
CONFIGS_DIR = os.path.join(BASE_DIR, "users", "configs")
|
|
||||||
|
|
||||||
def init_directory_structure():
|
|
||||||
"""
|
|
||||||
Inizializza la struttura delle directory necessarie per l'applicazione
|
|
||||||
"""
|
|
||||||
# Crea directory per utenti e configurazioni
|
|
||||||
os.makedirs(os.path.dirname(USERS_FILE), exist_ok=True)
|
|
||||||
os.makedirs(CONFIGS_DIR, exist_ok=True)
|
|
||||||
|
|
||||||
# Se il file users.json non esiste, crealo vuoto
|
|
||||||
if not os.path.exists(USERS_FILE):
|
|
||||||
with open(USERS_FILE, 'w') as f:
|
|
||||||
json.dump({}, f)
|
|
||||||
|
|
||||||
print(f"Initialized directory structure:")
|
|
||||||
print(f"Users file: {USERS_FILE}")
|
|
||||||
print(f"Configs directory: {CONFIGS_DIR}")
|
|
||||||
|
|
||||||
def hash_password(password):
|
|
||||||
"""Hash la password usando SHA-256"""
|
|
||||||
return hashlib.sha256(password.encode()).hexdigest()
|
|
||||||
|
|
||||||
# In auth/utils.py
|
|
||||||
def create_user(username, password):
|
|
||||||
"""
|
|
||||||
Crea un nuovo utente
|
|
||||||
Args:
|
|
||||||
username: nome utente
|
|
||||||
password: password in chiaro
|
|
||||||
Returns:
|
|
||||||
tuple: (success: bool, message: str)
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
print(f"Tentativo di creazione utente: {username}")
|
|
||||||
|
|
||||||
# Inizializza la struttura delle directory
|
|
||||||
init_directory_structure()
|
|
||||||
|
|
||||||
# Inizializza o carica il dizionario degli utenti
|
|
||||||
users = {}
|
|
||||||
if os.path.exists(USERS_FILE):
|
|
||||||
try:
|
|
||||||
with open(USERS_FILE, 'r') as f:
|
|
||||||
content = f.read()
|
|
||||||
if content.strip(): # Verifica che il file non sia vuoto
|
|
||||||
users = json.loads(content)
|
|
||||||
print(f"Utenti esistenti: {len(users)}")
|
|
||||||
except json.JSONDecodeError as e:
|
|
||||||
print(f"Errore nel parsing del file utenti: {e}")
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Validazioni
|
|
||||||
if not username or len(username) < 3:
|
|
||||||
return False, "Username deve essere almeno 3 caratteri"
|
|
||||||
if not password or len(password) < 6:
|
|
||||||
return False, "Password deve essere almeno 6 caratteri"
|
|
||||||
if username in users:
|
|
||||||
return False, "Username già esistente"
|
|
||||||
|
|
||||||
# Genera il salt e hash della password
|
|
||||||
salt = secrets.token_hex(8)
|
|
||||||
password_hash = hashlib.sha256((password + salt).encode()).hexdigest()
|
|
||||||
|
|
||||||
# Ottieni il percorso della configurazione utente
|
|
||||||
user_config = get_user_config_path(username)
|
|
||||||
print(f"Percorso configurazione utente: {user_config}")
|
|
||||||
|
|
||||||
# Crea la configurazione dell'utente
|
|
||||||
os.makedirs(os.path.dirname(user_config), exist_ok=True)
|
|
||||||
|
|
||||||
# Salva la configurazione di default
|
|
||||||
default_config = get_default_config()
|
|
||||||
with open(user_config, 'w') as f:
|
|
||||||
json.dump(default_config, f, indent=4)
|
|
||||||
print("Configurazione default salvata")
|
|
||||||
|
|
||||||
# Aggiungi nuovo utente con struttura semplificata
|
|
||||||
users[username] = {
|
|
||||||
"salt": salt,
|
|
||||||
"password_hash": password_hash
|
|
||||||
}
|
|
||||||
|
|
||||||
# Salva il file utenti
|
|
||||||
with open(USERS_FILE, 'w') as f:
|
|
||||||
json.dump(users, f, indent=4)
|
|
||||||
print("File utenti aggiornato con successo")
|
|
||||||
|
|
||||||
return True, "Utente creato con successo"
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Errore nella creazione dell'utente: {str(e)}")
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
return False, f"Errore nella creazione dell'utente: {str(e)}"
|
|
||||||
|
|
||||||
def verify_user(username, password):
|
|
||||||
"""
|
|
||||||
Verifica le credenziali utente usando salt e hash
|
|
||||||
Args:
|
|
||||||
username: nome utente
|
|
||||||
password: password in chiaro
|
|
||||||
Returns:
|
|
||||||
bool: True se le credenziali sono valide, False altrimenti
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if not os.path.exists(USERS_FILE):
|
|
||||||
print("File utenti non trovato")
|
|
||||||
return False
|
|
||||||
|
|
||||||
with open(USERS_FILE, 'r') as f:
|
|
||||||
users = json.load(f)
|
|
||||||
|
|
||||||
if username not in users:
|
|
||||||
print("Username non trovato")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Ottieni il salt e l'hash salvati
|
|
||||||
user_data = users[username]
|
|
||||||
stored_salt = user_data['salt']
|
|
||||||
stored_hash = user_data['password_hash']
|
|
||||||
|
|
||||||
# Calcola l'hash della password fornita con il salt salvato
|
|
||||||
password_hash = hashlib.sha256((password + stored_salt).encode()).hexdigest()
|
|
||||||
|
|
||||||
# Confronta gli hash
|
|
||||||
return stored_hash == password_hash
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Errore nella verifica dell'utente: {str(e)}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def create_token(username):
|
|
||||||
"""Crea JWT token"""
|
|
||||||
expiration = datetime.utcnow() + timedelta(hours=24)
|
|
||||||
return pyjwt.encode(
|
|
||||||
{"user": username, "exp": expiration},
|
|
||||||
SECRET_KEY,
|
|
||||||
algorithm="HS256"
|
|
||||||
)
|
|
||||||
|
|
||||||
def verify_token(token):
|
|
||||||
"""Verifica JWT token"""
|
|
||||||
try:
|
|
||||||
payload = pyjwt.decode(token, SECRET_KEY, algorithms=["HS256"])
|
|
||||||
return True, payload["user"]
|
|
||||||
except pyjwt.ExpiredSignatureError:
|
|
||||||
return False, "Token scaduto"
|
|
||||||
except pyjwt.InvalidTokenError:
|
|
||||||
return False, "Token non valido"
|
|
||||||
|
|
||||||
def get_user_config_path(username):
|
|
||||||
"""
|
|
||||||
Restituisce il percorso del file di configurazione per l'utente specificato
|
|
||||||
Args:
|
|
||||||
username: nome utente
|
|
||||||
Returns:
|
|
||||||
str: percorso assoluto del file di configurazione
|
|
||||||
"""
|
|
||||||
# Sostituisci caratteri non validi nel nome utente
|
|
||||||
safe_username = "".join(c for c in username if c.isalnum() or c in ('-', '_'))
|
|
||||||
|
|
||||||
# Costruisci il percorso assoluto
|
|
||||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
config_dir = os.path.join(base_dir, 'config', 'users')
|
|
||||||
config_path = os.path.join(config_dir, f"{safe_username}_config.json")
|
|
||||||
|
|
||||||
# Assicurati che la directory esista
|
|
||||||
os.makedirs(os.path.dirname(config_path), exist_ok=True)
|
|
||||||
|
|
||||||
return config_path
|
|
||||||
|
|
||||||
def get_default_config():
|
|
||||||
return {
|
|
||||||
"oliveto": {
|
|
||||||
"hectares": 1,
|
|
||||||
"varieties": [
|
|
||||||
{
|
|
||||||
"variety": "Nocellara dell'Etna",
|
|
||||||
"technique": "tradizionale",
|
|
||||||
"percentage": 50
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"variety": "Frantoio",
|
|
||||||
"technique": "tradizionale",
|
|
||||||
"percentage": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"variety": "Coratina",
|
|
||||||
"technique": "tradizionale",
|
|
||||||
"percentage": 40
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"costs": {
|
|
||||||
"fixed": {
|
|
||||||
"ammortamento": 2000,
|
|
||||||
"assicurazione": 500,
|
|
||||||
"manutenzione": 800,
|
|
||||||
"certificazioni": 3000
|
|
||||||
},
|
|
||||||
"variable": {
|
|
||||||
"raccolta": 0.35,
|
|
||||||
"potatura": 600,
|
|
||||||
"fertilizzanti": 400,
|
|
||||||
"irrigazione": 300
|
|
||||||
},
|
|
||||||
"transformation": {
|
|
||||||
"molitura": 0.15,
|
|
||||||
"stoccaggio": 0.2,
|
|
||||||
"bottiglia": 1.2,
|
|
||||||
"etichettatura": 0.3
|
|
||||||
},
|
|
||||||
"marketing": {
|
|
||||||
"budget_annuale": 15000,
|
|
||||||
"costi_commerciali": 0.5,
|
|
||||||
"prezzo_vendita": 12,
|
|
||||||
"perc_vendita_diretta": 30
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"inference": {
|
|
||||||
"debug_mode": True,
|
|
||||||
'model_path': './sources/olive_oil_transformer/olive_oil_transformer_model.keras'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,105 +0,0 @@
|
|||||||
# components/ids.py
|
|
||||||
from dataclasses import dataclass
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Ids:
|
|
||||||
# Auth Container
|
|
||||||
USE_MODEL = 'use-model'
|
|
||||||
AUTH_CONTAINER = 'auth-container'
|
|
||||||
DASHBOARD_CONTAINER = 'dashboard-container'
|
|
||||||
|
|
||||||
# Login Form
|
|
||||||
LOGIN_FORM = 'login-form'
|
|
||||||
LOGIN_USERNAME = 'login-username'
|
|
||||||
LOGIN_PASSWORD = 'login-password'
|
|
||||||
LOGIN_BUTTON = 'login-button'
|
|
||||||
LOGIN_ERROR = 'login-error'
|
|
||||||
|
|
||||||
# Register Form
|
|
||||||
REGISTER_FORM = 'register-form'
|
|
||||||
REGISTER_USERNAME = 'register-username'
|
|
||||||
REGISTER_PASSWORD = 'register-password'
|
|
||||||
REGISTER_CONFIRM = 'register-confirm'
|
|
||||||
REGISTER_BUTTON = 'register-button'
|
|
||||||
REGISTER_ERROR = 'register-error'
|
|
||||||
REGISTER_SUCCESS = 'register-success'
|
|
||||||
|
|
||||||
# Navigation
|
|
||||||
SHOW_REGISTER_BUTTON = 'show-register-button'
|
|
||||||
SHOW_LOGIN_BUTTON = 'show-login-button'
|
|
||||||
|
|
||||||
# Inference
|
|
||||||
INFERENCE_CONTAINER = 'inference-container'
|
|
||||||
INFERENCE_STATUS = 'inference-status'
|
|
||||||
INFERENCE_MODE = 'inference-mode'
|
|
||||||
INFERENCE_LATENCY = 'inference-latency'
|
|
||||||
INFERENCE_REQUESTS = 'inference-requests'
|
|
||||||
INFERENCE_COUNTER = 'inference-counter'
|
|
||||||
DEBUG_SWITCH = 'debug-switch'
|
|
||||||
|
|
||||||
# Simulation
|
|
||||||
SIMULATE_BUTTON = 'simulate-btn'
|
|
||||||
GROWTH_CHART = 'growth-simulation-chart'
|
|
||||||
PRODUCTION_CHART = 'production-simulation-chart'
|
|
||||||
SIMULATION_SUMMARY = 'simulation-summary'
|
|
||||||
KPI_CONTAINER = 'kpi-container'
|
|
||||||
PRODUCTION_DEBUG_SWITCH = 'production-debug-switch'
|
|
||||||
PRODUCTION_INFERENCE_REQUESTS = 'production-inference-requests'
|
|
||||||
PRODUCTION_INFERENCE_MODE = 'production-inference-mode'
|
|
||||||
|
|
||||||
# Environment Controls
|
|
||||||
TEMP_SLIDER = 'temp-slider'
|
|
||||||
HUMIDITY_SLIDER = 'humidity-slider'
|
|
||||||
RAINFALL_INPUT = 'rainfall-input'
|
|
||||||
RADIATION_INPUT = 'radiation-input'
|
|
||||||
|
|
||||||
# Production Views
|
|
||||||
OLIVE_PRODUCTION_HA = 'olive-production_ha'
|
|
||||||
OIL_PRODUCTION_HA = 'oil-production_ha'
|
|
||||||
WATER_NEED_HA = 'water-need_ha'
|
|
||||||
OLIVE_PRODUCTION = 'olive-production'
|
|
||||||
OIL_PRODUCTION = 'oil-production'
|
|
||||||
WATER_NEED = 'water-need'
|
|
||||||
PRODUCTION_DETAILS = 'production-details'
|
|
||||||
WEATHER_IMPACT = 'weather-impact'
|
|
||||||
WATER_NEEDS = 'water-needs'
|
|
||||||
EXTRA_INFO = 'extra-info'
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
HECTARES_INPUT = 'hectares-input'
|
|
||||||
VARIETY_1_DROPDOWN = 'variety-1-dropdown'
|
|
||||||
TECHNIQUE_1_DROPDOWN = 'technique-1-dropdown'
|
|
||||||
PERCENTAGE_1_INPUT = 'percentage-1-input'
|
|
||||||
VARIETY_2_DROPDOWN = 'variety-2-dropdown'
|
|
||||||
TECHNIQUE_2_DROPDOWN = 'technique-2-dropdown'
|
|
||||||
PERCENTAGE_2_INPUT = 'percentage-2-input'
|
|
||||||
VARIETY_3_DROPDOWN = 'variety-3-dropdown'
|
|
||||||
TECHNIQUE_3_DROPDOWN = 'technique-3-dropdown'
|
|
||||||
PERCENTAGE_3_INPUT = 'percentage-3-input'
|
|
||||||
PERCENTAGE_WARNING = 'percentage-warning'
|
|
||||||
|
|
||||||
# Cost Inputs
|
|
||||||
COST_AMMORTAMENTO = 'cost-ammortamento'
|
|
||||||
COST_ASSICURAZIONE = 'cost-assicurazione'
|
|
||||||
COST_MANUTENZIONE = 'cost-manutenzione'
|
|
||||||
COST_CERTIFICAZIONI = 'cost-certificazioni'
|
|
||||||
COST_RACCOLTA = 'cost-raccolta'
|
|
||||||
COST_POTATURA = 'cost-potatura'
|
|
||||||
COST_FERTILIZZANTI = 'cost-fertilizzanti'
|
|
||||||
COST_IRRIGAZIONE = 'cost-irrigazione'
|
|
||||||
COST_MOLITURA = 'cost-molitura'
|
|
||||||
COST_STOCCAGGIO = 'cost-stoccaggio'
|
|
||||||
COST_BOTTIGLIA = 'cost-bottiglia'
|
|
||||||
COST_ETICHETTATURA = 'cost-etichettatura'
|
|
||||||
COST_MARKETING = 'cost-marketing'
|
|
||||||
COST_COMMERCIALI = 'cost-commerciali'
|
|
||||||
PRICE_OLIO = 'price-olio'
|
|
||||||
PERC_VENDITA_DIRETTA = 'perc-vendita-diretta'
|
|
||||||
|
|
||||||
# Other
|
|
||||||
LOADING_ALERT = 'loading-alert'
|
|
||||||
TABS = 'tabs'
|
|
||||||
SAVE_CONFIG_BUTTON = 'save-config-button'
|
|
||||||
SAVE_CONFIG_MESSAGE = 'save-config-message'
|
|
||||||
LOGOUT_BUTTON = 'logout-button'
|
|
||||||
DEV_MODE = 'dev-mode'
|
|
||||||
Binary file not shown.
BIN
src/dashboard/__pycache__/environmental_simulator.cpython-39.pyc
Executable file
BIN
src/dashboard/__pycache__/environmental_simulator.cpython-39.pyc
Executable file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"oliveto": {
|
"oliveto": {
|
||||||
"hectares": 1,
|
"hectares": 4.35,
|
||||||
"varieties": [
|
"varieties": [
|
||||||
{
|
{
|
||||||
"variety": "Nocellara dell'Etna",
|
"variety": "Nocellara dell'Etna",
|
||||||
@ -10,12 +10,12 @@
|
|||||||
{
|
{
|
||||||
"variety": "Frantoio",
|
"variety": "Frantoio",
|
||||||
"technique": "tradizionale",
|
"technique": "tradizionale",
|
||||||
"percentage": 20
|
"percentage": 10
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"variety": "Coratina",
|
"variety": "Coratina",
|
||||||
"technique": "tradizionale",
|
"technique": "tradizionale",
|
||||||
"percentage": 30
|
"percentage": 40
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -46,7 +46,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"inference": {
|
"inference": {
|
||||||
"debug_mode": false,
|
"debug_mode": false
|
||||||
"model_path": "./sources/olive_oil_transformer/olive_oil_transformer_model.keras"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,65 +0,0 @@
|
|||||||
# Olive Oil Production Training Dataset Generator
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
This Python script generates a synthetic training dataset for olive oil production simulation. It simulates various factors affecting olive production including weather conditions, olive varieties, cultivation techniques, and geographical zones.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
- Parallel processing for efficient dataset generation
|
|
||||||
- Batch processing to manage memory usage
|
|
||||||
- Configurable simulation parameters
|
|
||||||
- Weather effect calculations
|
|
||||||
- Multiple olive varieties and cultivation techniques support
|
|
||||||
- Zone-based production simulation
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
Required Python packages:
|
|
||||||
- pandas
|
|
||||||
- numpy
|
|
||||||
- psutil
|
|
||||||
- tqdm
|
|
||||||
- concurrent.futures (part of Python standard library)
|
|
||||||
- multiprocessing (part of Python standard library)
|
|
||||||
|
|
||||||
Required input data files:
|
|
||||||
- `./sources/weather_data_solarenergy.parquet`: Weather data including solar energy measurements
|
|
||||||
- `./sources/olive_varieties.parquet`: Olive varieties and their characteristics
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Command Line Arguments
|
|
||||||
```bash
|
|
||||||
python olive_oil_train_dataset.create_train_dataset [options]
|
|
||||||
```
|
|
||||||
|
|
||||||
Options:
|
|
||||||
- `--random-seed`: Seed for reproducible results (optional)
|
|
||||||
- `--num-simulations`: Total number of simulations to run (default: 100000)
|
|
||||||
- `--num-zones`: Number of zones per simulation (default: same as num-simulations)
|
|
||||||
- `--batch-size`: Size of each simulation batch (default: 10000)
|
|
||||||
- `--output-path`: Output file path (default: './sources/olive_training_dataset.parquet')
|
|
||||||
- `--max-workers`: Number of parallel workers (default: automatically optimized)
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```bash
|
|
||||||
python olive_oil_train_dataset.create_train_dataset --num-simulations 50 --num-zones 10 --batch-size 50 --output-path "./output/olive_dataset.parquet"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output
|
|
||||||
The script generates a Parquet file containing simulated olive production data with the following key features:
|
|
||||||
- Simulation and zone identifiers
|
|
||||||
- Weather conditions (temperature, precipitation, solar energy)
|
|
||||||
- Production metrics per olive variety
|
|
||||||
- Oil yield calculations
|
|
||||||
- Water requirements
|
|
||||||
- Cultivation techniques
|
|
||||||
|
|
||||||
## Technical Details
|
|
||||||
|
|
||||||
### Simulation Parameters
|
|
||||||
The simulation takes into account:
|
|
||||||
- Temperature effects on production
|
|
||||||
- Water availability and drought resistance
|
|
||||||
- Solar radiation impact
|
|
||||||
- Variety-specific characteristics
|
|
||||||
- Cultivation technique influence
|
|
||||||
- Zone-specific variations
|
|
||||||
Binary file not shown.
BIN
src/olive_oil_train_dataset/__pycache__/create_train_dataset.cpython-39.pyc
Executable file
BIN
src/olive_oil_train_dataset/__pycache__/create_train_dataset.cpython-39.pyc
Executable file
Binary file not shown.
@ -133,24 +133,22 @@ def simulate_zone(base_weather, olive_varieties, year, zone, all_varieties, vari
|
|||||||
variety_info['Fabbisogno Acqua Estate (m³/ettaro)'] +
|
variety_info['Fabbisogno Acqua Estate (m³/ettaro)'] +
|
||||||
variety_info['Fabbisogno Acqua Autunno (m³/ettaro)'] +
|
variety_info['Fabbisogno Acqua Autunno (m³/ettaro)'] +
|
||||||
variety_info['Fabbisogno Acqua Inverno (m³/ettaro)']
|
variety_info['Fabbisogno Acqua Inverno (m³/ettaro)']
|
||||||
) / 12
|
) / 4
|
||||||
|
|
||||||
monthly_water_need = zone_weather.apply(
|
monthly_water_need = zone_weather.apply(
|
||||||
lambda row: calculate_water_need(row, base_water_need, variety_info['Temperatura Ottimale']),
|
lambda row: calculate_water_need(row, base_water_need, variety_info['Temperatura Ottimale']),
|
||||||
axis=1
|
axis=1
|
||||||
)
|
)
|
||||||
#print(f'Monthly - {variety} - hectares {hectares} - {monthly_water_need}')
|
|
||||||
monthly_water_need *= np.random.uniform(0.95, 1.05, len(monthly_water_need))
|
monthly_water_need *= np.random.uniform(0.95, 1.05, len(monthly_water_need))
|
||||||
#print(f'Monthly 2 - {variety} - hectares {hectares} - {monthly_water_need}')
|
|
||||||
annual_variety_water_need = monthly_water_need.sum() * percentage * hectares
|
annual_variety_water_need = monthly_water_need.sum() * percentage * hectares
|
||||||
#print(f'Annual Variety - {variety} - hectares {hectares} - {annual_variety_water_need}')
|
|
||||||
# Aggiorna totali annuali
|
# Aggiorna totali annuali
|
||||||
annual_production += annual_variety_production
|
annual_production += annual_variety_production
|
||||||
annual_min_oil += min_oil_production
|
annual_min_oil += min_oil_production
|
||||||
annual_max_oil += max_oil_production
|
annual_max_oil += max_oil_production
|
||||||
annual_avg_oil += avg_oil_production
|
annual_avg_oil += avg_oil_production
|
||||||
annual_water_need += annual_variety_water_need
|
annual_water_need += annual_variety_water_need
|
||||||
#print(f'Total Annual {annual_water_need}')
|
|
||||||
# Aggiorna dati varietà
|
# Aggiorna dati varietà
|
||||||
clean_variety = clean_column_name(variety)
|
clean_variety = clean_column_name(variety)
|
||||||
variety_data[clean_variety].update({
|
variety_data[clean_variety].update({
|
||||||
@ -242,9 +240,9 @@ def simulate_olive_production_parallel(weather_data, olive_varieties, num_simula
|
|||||||
print(f"Utilizzando {max_workers} workers ottimali basati sulle risorse del sistema")
|
print(f"Utilizzando {max_workers} workers ottimali basati sulle risorse del sistema")
|
||||||
|
|
||||||
# Calcolo numero di batch
|
# Calcolo numero di batch
|
||||||
num_batches = (num_simulations * num_zones - 1) // batch_size
|
num_batches = (num_simulations + batch_size - 1) // batch_size
|
||||||
print(f"Elaborazione di {num_simulations} simulazioni con {num_zones} zone in {num_batches} batch")
|
print(f"Elaborazione di {num_simulations} simulazioni con {num_zones} zone in {num_batches} batch")
|
||||||
print(f"Totale record attesi: {num_simulations * num_zones}")
|
print(f"Totale record attesi: {num_simulations * num_zones:,}")
|
||||||
|
|
||||||
# Lista per contenere tutti i DataFrame dei batch
|
# Lista per contenere tutti i DataFrame dei batch
|
||||||
all_batches = []
|
all_batches = []
|
||||||
@ -370,11 +368,11 @@ def calculate_production(variety_info, weather, percentage, hectares, seed):
|
|||||||
variety_info['Fabbisogno Acqua Inverno (m³/ettaro)']
|
variety_info['Fabbisogno Acqua Inverno (m³/ettaro)']
|
||||||
) / 4 * percentage * hectares
|
) / 4 * percentage * hectares
|
||||||
|
|
||||||
temp_factor = 1 + max(0, (weather["temp_mean"] - 20) / 50)
|
water_need = (
|
||||||
rain_factor = max(0.6, 1 - (weather["precip_sum"] / 1000))
|
base_water_need *
|
||||||
water_need = base_water_need * temp_factor * rain_factor
|
(1 + max(0, (weather['temp_mean'] - 20) / 50)) *
|
||||||
|
max(0.6, 1 - (weather['precip_sum'] / 1000))
|
||||||
print(f'temp factor: {temp_factor} rainfall factor: {rain_factor} water_need: {water_need}')
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'variety': variety_info['Varietà di Olive'],
|
'variety': variety_info['Varietà di Olive'],
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# Data handling and analysis
|
# Data handling and analysis
|
||||||
pandas>=1.5.0
|
pandas>=1.5.0
|
||||||
numpy>=1.21.0
|
numpy>=1.21.0
|
||||||
scikit-learn==1.6.0
|
scikit-learn==1.5.2
|
||||||
|
|
||||||
# Dashboard and visualization
|
# Dashboard and visualization
|
||||||
dash>=2.9.0
|
dash>=2.9.0
|
||||||
@ -19,6 +19,3 @@ psutil>=5.9.0
|
|||||||
|
|
||||||
# File handling
|
# File handling
|
||||||
dvc>=2.0.0 # Per la gestione dei file sources.dvc
|
dvc>=2.0.0 # Per la gestione dei file sources.dvc
|
||||||
|
|
||||||
# Auth
|
|
||||||
PyJWT==2.7.0
|
|
||||||
BIN
src/utils/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
src/utils/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
src/utils/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/__init__.cpython-39.pyc
Executable file
BIN
src/utils/__pycache__/__init__.cpython-39.pyc
Executable file
Binary file not shown.
BIN
src/utils/__pycache__/helpers.cpython-311.pyc
Normal file
BIN
src/utils/__pycache__/helpers.cpython-311.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/helpers.cpython-312.pyc
Normal file
BIN
src/utils/__pycache__/helpers.cpython-312.pyc
Normal file
Binary file not shown.
BIN
src/utils/__pycache__/helpers.cpython-39.pyc
Executable file
BIN
src/utils/__pycache__/helpers.cpython-39.pyc
Executable file
Binary file not shown.
@ -424,20 +424,10 @@ def calculate_weather_effect(row, optimal_temp):
|
|||||||
return combined_effect
|
return combined_effect
|
||||||
|
|
||||||
def calculate_water_need(weather_data, base_need, optimal_temp):
|
def calculate_water_need(weather_data, base_need, optimal_temp):
|
||||||
# Calcola il fattore temperatura (minimo 80% del fabbisogno)
|
# Calcola il fabbisogno idrico basato su temperatura e precipitazioni
|
||||||
temp_factor = max(0.8, 1 + 0.05 * (weather_data['temp_mean'] - optimal_temp))
|
temp_factor = 1 + 0.05 * (weather_data['temp_mean'] - optimal_temp) # Aumenta del 5% per ogni grado sopra l'ottimale
|
||||||
|
rain_factor = 1 - 0.001 * weather_data['precip_sum'] # Diminuisce leggermente con l'aumentare delle precipitazioni
|
||||||
# Calcola il fattore precipitazioni (minimo 50% del fabbisogno)
|
return base_need * temp_factor * rain_factor
|
||||||
rain_factor = max(0.5, 1 - 0.001 * weather_data['precip_sum'])
|
|
||||||
|
|
||||||
# Calcola il fabbisogno idrico totale
|
|
||||||
water_need = base_need * temp_factor * rain_factor
|
|
||||||
|
|
||||||
# Debug: controlla che il fabbisogno idrico sia positivo
|
|
||||||
assert water_need >= 0, "Il fabbisogno idrico calcolato è negativo!"
|
|
||||||
|
|
||||||
return water_need
|
|
||||||
|
|
||||||
|
|
||||||
def create_technique_mapping(olive_varieties, mapping_path='./sources/technique_mapping.joblib'):
|
def create_technique_mapping(olive_varieties, mapping_path='./sources/technique_mapping.joblib'):
|
||||||
# Estrai tutte le tecniche uniche dal dataset e convertile in lowercase
|
# Estrai tutte le tecniche uniche dal dataset e convertile in lowercase
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user