Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

143 lignes
5.7 KiB

  1. import streamlit as st
  2. import pandas as pd
  3. import os
  4. import json
  5. import shutil
  6. import time
  7. import joblib
  8. from pathlib import Path
  9. def get_campaigns_info(directory: Path):
  10. """Raggruppa i file per prefisso campagna."""
  11. if not directory.exists(): return {}
  12. files = list(directory.glob("*.csv"))
  13. campaigns = {}
  14. for f in files:
  15. parts = f.name.split('_')
  16. if len(parts) >= 4:
  17. camp_id = parts[0]
  18. campaigns.setdefault(camp_id, []).append(str(f))
  19. return campaigns
  20. def show_training_data_manager(cfg):
  21. st.subheader("🧠 Console Gestione Modelli e Rilievi")
  22. MODEL_DIR = Path("/data/model")
  23. JOBS_DIR = Path("/data/train/train_jobs")
  24. MODEL_DIR.mkdir(parents=True, exist_ok=True)
  25. JOBS_DIR.mkdir(parents=True, exist_ok=True)
  26. # --- 1. GESTIONE MODELLI E LINK SIMBOLICO ---
  27. st.write("### 🎯 Modelli Generati ed Attivazione")
  28. available_models = sorted(
  29. [m for m in MODEL_DIR.glob("model_camp_*.joblib")],
  30. key=os.path.getmtime,
  31. reverse=True
  32. )
  33. if available_models:
  34. # Visualizzazione stato attuale link simbolico
  35. target_path = MODEL_DIR / "model.joblib"
  36. if target_path.is_symlink():
  37. try:
  38. current_link = os.readlink(target_path)
  39. st.info(f"🔗 **Modello operativo attuale:** `{os.path.basename(current_link)}`")
  40. except Exception:
  41. st.warning("⚠️ Impossibile leggere il link simbolico.")
  42. # Tabella modelli esistenti
  43. m_list = []
  44. for m in available_models:
  45. m_list.append({
  46. "Nome Modello": m.name,
  47. "Data": time.strftime('%d/%m/%Y %H:%M', time.localtime(m.stat().st_mtime)),
  48. "Size": f"{round(m.stat().st_size / 1024, 1)} KB"
  49. })
  50. st.dataframe(pd.DataFrame(m_list), use_container_width=True, hide_index=True)
  51. selected_model = st.selectbox("Scegli il modello da analizzare o attivare:", [m.name for m in available_models])
  52. # --- NUOVA SEZIONE: ANALISI TECNICA ---
  53. with st.expander("🔍 Ispezione Metadati Modello", expanded=False):
  54. try:
  55. m_data = joblib.load(MODEL_DIR / selected_model)
  56. st.write(f"**Data Creazione:** {m_data.get('created_at', 'N/D')}")
  57. st.write(f"**Gateway allenati:** {len(m_data.get('gateways_order', []))}")
  58. st.code(", ".join(m_data.get('gateways_order', [])))
  59. floors = list(m_data.get('xy_by_floor', {}).keys())
  60. st.write(f"**Piani mappati nel regressore:** {floors}")
  61. if not floors or len(m_data.get('gateways_order', [])) == 0:
  62. st.error("⚠️ Attenzione: Il modello sembra non contenere dati validi.")
  63. except Exception as e:
  64. st.error(f"Errore caricamento per analisi: {e}")
  65. if st.button("🔗 IMPOSTA COME OPERATIVO (Symlink)", type="primary", use_container_width=True):
  66. try:
  67. if target_path.exists() or target_path.is_symlink():
  68. target_path.unlink()
  69. current_dir = os.getcwd()
  70. os.chdir(str(MODEL_DIR))
  71. os.symlink(selected_model, "model.joblib")
  72. os.chdir(current_dir)
  73. st.success(f"Link aggiornato con successo a {selected_model}")
  74. time.sleep(1)
  75. st.rerun()
  76. except Exception as e:
  77. st.error(f"Errore: {e}")
  78. else:
  79. st.info("Nessun modello disponibile.")
  80. st.divider()
  81. # --- 2. ISPEZIONE RILIEVI E NUOVO ADDESTRAMENTO ---
  82. st.write("### 🚀 Analisi Dati e Nuovo Addestramento")
  83. train_cfg = cfg.get("train", {})
  84. samples_dir = Path(train_cfg.get("samples_dir", "/data/train/samples"))
  85. campaigns_map = get_campaigns_info(samples_dir)
  86. if not campaigns_map:
  87. st.info("Nessun dato di rilievo trovato."); return
  88. camp_list = sorted(campaigns_map.keys())
  89. selected_camp = st.radio("Seleziona Campagna:", camp_list, horizontal=True)
  90. current_files = campaigns_map[selected_camp]
  91. files_df = pd.DataFrame([
  92. {"File": os.path.basename(f), "Size": f"{round(os.path.getsize(f)/1024, 1)} KB", "Path": f}
  93. for f in current_files
  94. ]).sort_values("File")
  95. st.dataframe(files_df[["File", "Size"]], use_container_width=True, hide_index=True)
  96. sel_file = st.selectbox("Ispeziona contenuto file CSV:", ["-- seleziona --"] + files_df["File"].tolist())
  97. if sel_file != "-- seleziona --":
  98. f_path = files_df[files_df["File"] == sel_file]["Path"].iloc[0]
  99. try:
  100. delim = cfg.get('paths', {}).get('csv_delimiter', ';')
  101. st.dataframe(pd.read_csv(f_path, sep=delim), use_container_width=True)
  102. except Exception as e:
  103. st.error(f"Errore lettura: {e}")
  104. # Bottone di Addestramento
  105. pending_jobs = list(JOBS_DIR.glob("*.lock"))
  106. if pending_jobs:
  107. st.warning(f"⏳ Addestramento in corso: {pending_jobs[0].name}")
  108. else:
  109. if st.button(f"🏋️ AVVIA ADDESTRAMENTO CAMPAGNA {selected_camp}", type="primary", use_container_width=True):
  110. job_data = {
  111. "campaign": selected_camp,
  112. "knn": train_cfg.get("knn", {}),
  113. "nan_fill": train_cfg.get("nan_fill", -110),
  114. "gateways_csv": train_cfg.get("gateways_csv", "/data/config/gateway.csv"),
  115. "timestamp": time.time()
  116. }
  117. with open(JOBS_DIR / f"train_{selected_camp}.lock", "w") as f:
  118. json.dump(job_data, f)
  119. st.success("Richiesta inviata al Core.")
  120. time.sleep(1)
  121. st.rerun()