|
- import streamlit as st
- import pandas as pd
- import os
- import json
- import shutil
- import time
- import joblib
- from pathlib import Path
-
- def get_campaigns_info(directory: Path):
- """Raggruppa i file per prefisso campagna."""
- if not directory.exists(): return {}
- files = list(directory.glob("*.csv"))
- campaigns = {}
- for f in files:
- parts = f.name.split('_')
- if len(parts) >= 4:
- camp_id = parts[0]
- campaigns.setdefault(camp_id, []).append(str(f))
- return campaigns
-
- def show_training_data_manager(cfg):
- st.subheader("🧠 Console Gestione Modelli e Rilievi")
-
- MODEL_DIR = Path("/data/model")
- JOBS_DIR = Path("/data/train/train_jobs")
- MODEL_DIR.mkdir(parents=True, exist_ok=True)
- JOBS_DIR.mkdir(parents=True, exist_ok=True)
-
- # --- 1. GESTIONE MODELLI E LINK SIMBOLICO ---
- st.write("### 🎯 Modelli Generati ed Attivazione")
-
- available_models = sorted(
- [m for m in MODEL_DIR.glob("model_camp_*.joblib")],
- key=os.path.getmtime,
- reverse=True
- )
-
- if available_models:
- # Visualizzazione stato attuale link simbolico
- target_path = MODEL_DIR / "model.joblib"
- if target_path.is_symlink():
- try:
- current_link = os.readlink(target_path)
- st.info(f"🔗 **Modello operativo attuale:** `{os.path.basename(current_link)}`")
- except Exception:
- st.warning("⚠️ Impossibile leggere il link simbolico.")
-
- # Tabella modelli esistenti
- m_list = []
- for m in available_models:
- m_list.append({
- "Nome Modello": m.name,
- "Data": time.strftime('%d/%m/%Y %H:%M', time.localtime(m.stat().st_mtime)),
- "Size": f"{round(m.stat().st_size / 1024, 1)} KB"
- })
- st.dataframe(pd.DataFrame(m_list), use_container_width=True, hide_index=True)
-
- selected_model = st.selectbox("Scegli il modello da analizzare o attivare:", [m.name for m in available_models])
-
- # --- NUOVA SEZIONE: ANALISI TECNICA ---
- with st.expander("🔍 Ispezione Metadati Modello", expanded=False):
- try:
- m_data = joblib.load(MODEL_DIR / selected_model)
- st.write(f"**Data Creazione:** {m_data.get('created_at', 'N/D')}")
- st.write(f"**Gateway allenati:** {len(m_data.get('gateways_order', []))}")
- st.code(", ".join(m_data.get('gateways_order', [])))
-
- floors = list(m_data.get('xy_by_floor', {}).keys())
- st.write(f"**Piani mappati nel regressore:** {floors}")
-
- if not floors or len(m_data.get('gateways_order', [])) == 0:
- st.error("⚠️ Attenzione: Il modello sembra non contenere dati validi.")
- except Exception as e:
- st.error(f"Errore caricamento per analisi: {e}")
-
- if st.button("🔗 IMPOSTA COME OPERATIVO (Symlink)", type="primary", use_container_width=True):
- try:
- if target_path.exists() or target_path.is_symlink():
- target_path.unlink()
- current_dir = os.getcwd()
- os.chdir(str(MODEL_DIR))
- os.symlink(selected_model, "model.joblib")
- os.chdir(current_dir)
- st.success(f"Link aggiornato con successo a {selected_model}")
- time.sleep(1)
- st.rerun()
- except Exception as e:
- st.error(f"Errore: {e}")
- else:
- st.info("Nessun modello disponibile.")
-
- st.divider()
-
- # --- 2. ISPEZIONE RILIEVI E NUOVO ADDESTRAMENTO ---
- st.write("### 🚀 Analisi Dati e Nuovo Addestramento")
-
- train_cfg = cfg.get("train", {})
- samples_dir = Path(train_cfg.get("samples_dir", "/data/train/samples"))
- campaigns_map = get_campaigns_info(samples_dir)
-
- if not campaigns_map:
- st.info("Nessun dato di rilievo trovato."); return
-
- camp_list = sorted(campaigns_map.keys())
- selected_camp = st.radio("Seleziona Campagna:", camp_list, horizontal=True)
-
- current_files = campaigns_map[selected_camp]
- files_df = pd.DataFrame([
- {"File": os.path.basename(f), "Size": f"{round(os.path.getsize(f)/1024, 1)} KB", "Path": f}
- for f in current_files
- ]).sort_values("File")
-
- st.dataframe(files_df[["File", "Size"]], use_container_width=True, hide_index=True)
-
- sel_file = st.selectbox("Ispeziona contenuto file CSV:", ["-- seleziona --"] + files_df["File"].tolist())
- if sel_file != "-- seleziona --":
- f_path = files_df[files_df["File"] == sel_file]["Path"].iloc[0]
- try:
- delim = cfg.get('paths', {}).get('csv_delimiter', ';')
- st.dataframe(pd.read_csv(f_path, sep=delim), use_container_width=True)
- except Exception as e:
- st.error(f"Errore lettura: {e}")
-
- # Bottone di Addestramento
- pending_jobs = list(JOBS_DIR.glob("*.lock"))
- if pending_jobs:
- st.warning(f"⏳ Addestramento in corso: {pending_jobs[0].name}")
- else:
- if st.button(f"🏋️ AVVIA ADDESTRAMENTO CAMPAGNA {selected_camp}", type="primary", use_container_width=True):
- job_data = {
- "campaign": selected_camp,
- "knn": train_cfg.get("knn", {}),
- "nan_fill": train_cfg.get("nan_fill", -110),
- "gateways_csv": train_cfg.get("gateways_csv", "/data/config/gateway.csv"),
- "timestamp": time.time()
- }
- with open(JOBS_DIR / f"train_{selected_camp}.lock", "w") as f:
- json.dump(job_data, f)
- st.success("Richiesta inviata al Core.")
- time.sleep(1)
- st.rerun()
|