import streamlit as st import requests import pandas as pd API_BASE = "http://localhost:8000/api/v1" EXPOSURE_ROUTES = ["Dermal", "Oral", "Inhalation", "Ocular"] RITENZIONE_PRESETS = { "Leave-on (1.0)": 1.0, "Rinse-off (0.01)": 0.01, "Dentifricio (0.05)": 0.05, "Collutorio (0.10)": 0.10, "Tintura (0.10)": 0.10, } st.set_page_config(page_title="Gestione Esposizione", layout="wide") st.title("Gestione Preset Esposizione") tab_crea, tab_lista = st.tabs(["Crea Preset", "Preset Esistenti"]) # --- TAB CREAZIONE --- with tab_crea: st.subheader("Nuovo Preset di Esposizione") col1, col2 = st.columns(2) with col1: preset_name = st.text_input("Nome Preset", placeholder="es. Crema viso leave-on") tipo_prodotto = st.text_input("Tipo Prodotto", placeholder="es. Crema") luogo_applicazione = st.text_input("Luogo Applicazione", placeholder="es. Viso") with col2: sup_esposta = st.number_input("Superficie esposta (cm2)", min_value=1, max_value=17500, value=565) freq_applicazione = st.number_input("Frequenza applicazione (al giorno)", min_value=0.01, value=1.0, step=0.01, format="%.2f") qta_giornaliera = st.number_input("Quantita giornaliera (g/die)", min_value=0.01, value=1.54, step=0.01, format="%.2f") st.markdown("---") col3, col4, col5 = st.columns(3) with col3: st.markdown("**Vie esposizione normali**") esp_normali = st.multiselect("Normali", EXPOSURE_ROUTES, default=["Dermal"], key="esp_norm") with col4: st.markdown("**Vie esposizione secondarie**") esp_secondarie = st.multiselect("Secondarie", EXPOSURE_ROUTES, default=[], key="esp_sec") with col5: st.markdown("**Vie esposizione nano**") esp_nano = st.multiselect("Nano", EXPOSURE_ROUTES, default=["Dermal"], key="esp_nano") st.markdown("---") ritenzione_label = st.selectbox("Fattore di ritenzione", list(RITENZIONE_PRESETS.keys())) ritenzione = RITENZIONE_PRESETS[ritenzione_label] # Preview payload payload = { "preset_name": preset_name, "tipo_prodotto": tipo_prodotto, "luogo_applicazione": luogo_applicazione, "esp_normali": esp_normali, "esp_secondarie": esp_secondarie, "esp_nano": esp_nano, "sup_esposta": sup_esposta, "freq_applicazione": freq_applicazione, "qta_giornaliera": qta_giornaliera, "ritenzione": ritenzione, } with st.expander("Anteprima JSON"): st.json(payload) if st.button("Crea Preset", type="primary", disabled=not preset_name): try: resp = requests.post(f"{API_BASE}/esposition/create", json=payload, timeout=10) data = resp.json() if data.get("success"): st.success(f"Preset '{preset_name}' creato con successo (id: {data['data']['id_preset']})") else: st.error(f"Errore: {data.get('error', 'Sconosciuto')}") except requests.ConnectionError: st.error("Impossibile connettersi all'API. Verifica che il server sia attivo.") except Exception as e: st.error(f"Errore: {e}") # --- Session state --- if "confirm_delete_preset" not in st.session_state: st.session_state.confirm_delete_preset = None # --- TAB LISTA --- with tab_lista: st.subheader("Preset Esistenti") if st.button("Aggiorna lista"): st.session_state.confirm_delete_preset = None st.rerun() try: resp = requests.get(f"{API_BASE}/esposition/presets", timeout=10) data = resp.json() if data.get("success") and data.get("data"): st.info(f"Trovati {data['total']} preset") df = pd.DataFrame(data["data"]) display_cols = [ "preset_name", "tipo_prodotto", "luogo_applicazione", "sup_esposta", "freq_applicazione", "qta_giornaliera", "ritenzione", "esposizione_calcolata", "esposizione_relativa", ] existing = [c for c in display_cols if c in df.columns] st.dataframe(df[existing], use_container_width=True, hide_index=True) st.divider() st.subheader("Elimina Preset") for preset in data["data"]: name = preset.get("preset_name", "") col_name, col_btn = st.columns([4, 1]) col_name.write(f"**{name}**") if st.session_state.confirm_delete_preset == name: with col_btn: sub1, sub2 = st.columns(2) with sub1: if st.button("Si", key=f"confirm_{name}", type="primary", use_container_width=True): try: del_resp = requests.delete(f"{API_BASE}/esposition/delete/{name}", timeout=10) del_data = del_resp.json() if del_data.get("success"): st.success(f"Preset '{name}' eliminato") st.session_state.confirm_delete_preset = None st.rerun() else: st.error(del_data.get("error", "Errore eliminazione")) except Exception as e: st.error(f"Errore: {e}") with sub2: if st.button("No", key=f"cancel_{name}", use_container_width=True): st.session_state.confirm_delete_preset = None st.rerun() else: with col_btn: if st.button("Elimina", key=f"del_{name}", use_container_width=True): st.session_state.confirm_delete_preset = name st.rerun() else: st.warning("Nessun preset trovato.") except requests.ConnectionError: st.error("Impossibile connettersi all'API. Verifica che il server sia attivo.") except Exception as e: st.error(f"Errore nel caricamento: {e}")