import streamlit as st import requests import pandas as pd API_BASE = "https://api.cosmoguard.it/api/v1/" st.set_page_config(page_title="Ricerca Ingredienti", layout="wide") st.title("Ricerca Ingredienti per CAS") tab_ricerca, tab_risultato, tab_inventario = st.tabs(["Ricerca", "Risultato", "Inventario"]) # --- State --- if "ingredient_data" not in st.session_state: st.session_state.ingredient_data = None if "ingredient_cas" not in st.session_state: st.session_state.ingredient_cas = "" # --- TAB INVENTARIO --- with tab_inventario: st.subheader("Ingredienti gia acquisiti") if st.button("Aggiorna inventario"): st.rerun() try: resp = requests.get(f"{API_BASE}/ingredients/list", timeout=10) result = resp.json() if result.get("success") and result.get("data"): st.info(f"Trovati {result['total']} ingredienti nel database") df = pd.DataFrame(result["data"]) df["dap"] = df["dap"].map({True: "OK", False: "-"}) df["cosing"] = df["cosing"].map({True: "OK", False: "-"}) df["tox"] = df["tox"].map({True: "OK", False: "-"}) df = df.rename(columns={ "cas": "CAS", "dap": "DAP", "cosing": "COSING", "tox": "TOX", "created_at": "Data Acquisizione", }) display_cols = ["CAS", "DAP", "COSING", "TOX", "Data Acquisizione"] existing = [c for c in display_cols if c in df.columns] st.dataframe(df[existing], use_container_width=True, hide_index=True) else: st.warning("Nessun ingrediente trovato nel database.") 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}") # --- TAB RICERCA --- with tab_ricerca: st.subheader("Cerca un ingrediente") cas_input = st.text_input("CAS Number", placeholder="es. 64-17-5") if st.button("Cerca", type="primary", disabled=not cas_input): with st.spinner(f"Ricerca in corso per {cas_input}..."): try: resp = requests.post( f"{API_BASE}/ingredients/search", json={"cas": cas_input}, timeout=120, ) result = resp.json() if result.get("success") and result.get("data"): st.session_state.ingredient_data = result["data"] st.session_state.ingredient_cas = cas_input st.success(f"Ingrediente {cas_input} trovato") else: st.session_state.ingredient_data = None st.error(result.get("error", f"Nessun dato per CAS {cas_input}")) except requests.ConnectionError: st.error("Impossibile connettersi all'API. Verifica che il server sia attivo.") except Exception as e: st.error(f"Errore: {e}") # --- TAB RISULTATO --- with tab_risultato: data = st.session_state.ingredient_data if data is None: st.info("Effettua una ricerca per visualizzare i risultati.") else: cas = data.get("cas", "") st.subheader(f"Ingrediente: {cas}") # --- Header con INCI e data --- col_h1, col_h2 = st.columns(2) with col_h1: inci = data.get("inci") or [] st.markdown(f"**INCI:** {', '.join(inci) if inci else 'N/A'}") with col_h2: st.markdown(f"**Data creazione:** {data.get('creation_date', 'N/A')}") st.markdown("---") # --- DAP Info --- st.subheader("DAP Info") dap = data.get("dap_info") if dap: col_d1, col_d2, col_d3 = st.columns(3) with col_d1: st.metric("Peso Molecolare (Da)", dap.get("molecular_weight", "N/A")) st.metric("Log Pow", dap.get("log_pow", "N/A")) with col_d2: st.metric("TPSA", dap.get("tpsa", "N/A")) st.metric("Punto Fusione (C)", dap.get("melting_point") or "N/A") with col_d3: dap_val = dap.get("dap_value", 0.5) st.metric("DAP Value", f"{dap_val * 100:.0f}%") st.metric("Alta Ionizzazione", dap.get("high_ionization") or "N/A") else: st.warning("Dati DAP non disponibili") st.markdown("---") # --- COSING Info --- st.subheader("COSING Info") cosing_list = data.get("cosing_info") if cosing_list: for i, cosing in enumerate(cosing_list): if len(cosing_list) > 1: st.markdown(f"**Voce {i + 1}**") col_c1, col_c2 = st.columns(2) with col_c1: names = cosing.get("common_names", []) st.markdown(f"**Nomi comuni:** {', '.join(names) if names else 'N/A'}") funcs = cosing.get("functionName", []) if funcs: st.markdown("**Funzioni:**") for f in funcs: st.markdown(f"- {f}") with col_c2: annex = cosing.get("annex", []) if annex: st.markdown("**Annex/Restrizioni:**") for a in annex: st.markdown(f"- {a}") else: st.markdown("**Annex:** Nessuna restrizione") other = cosing.get("otherRestrictions", []) if other: st.markdown("**Altre restrizioni:**") for o in other: st.markdown(f"- {o}") restriction = cosing.get("cosmeticRestriction", "") if restriction: st.warning(f"Restrizione cosmetica: {restriction}") if i < len(cosing_list) - 1: st.divider() else: st.warning("Dati COSING non disponibili") st.markdown("---") # --- Toxicity --- st.subheader("Tossicologia") tox = data.get("toxicity") if tox: # Best case highlight best = tox.get("best_case") if best: st.success( f"Miglior indicatore: **{best['indicator']}** = {best['value']} {best['unit']} " f"({best['route']}) — Fattore: {tox.get('factor', 'N/A')}" ) # Indicators table indicators = tox.get("indicators", []) if indicators: df = pd.DataFrame(indicators) col_order = ["indicator", "value", "unit", "route", "toxicity_type"] existing = [c for c in col_order if c in df.columns] df = df[existing] df.columns = ["Indicatore", "Valore", "Unita", "Via", "Tipo"][:len(existing)] st.dataframe(df, use_container_width=True, hide_index=True) else: st.warning("Dati tossicologici non disponibili") st.markdown("---") # --- JSON completo --- with st.expander("JSON completo"): st.json(data)