From 1e5b9adeac6011f9cfcca6541124929b4244398a Mon Sep 17 00:00:00 2001 From: adish-rmr Date: Sat, 3 Jan 2026 11:29:38 +0100 Subject: [PATCH] add: inci search, multiple cas selection, added DAP, check if link exists before download --- app.py | 24 +++++++--- functions.py | 20 +++++--- functions_ui.py | 10 ++-- pages/dap.py | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 17 deletions(-) create mode 100644 pages/dap.py diff --git a/app.py b/app.py index 74ebb16..a04095b 100644 --- a/app.py +++ b/app.py @@ -1,6 +1,6 @@ import streamlit as st -from functions_ui import search_cas_number +from functions_ui import search_cas_inci # Configure page st.set_page_config( @@ -48,11 +48,16 @@ def home(): # Inizializza session_state per il CAS number se non esiste if 'selected_cas' not in st.session_state: st.session_state.selected_cas = None - - input = st.text_input("Enter CAS Number:", "") + + # choose between cas or inci + type = st.radio("Search by:", ("CAS Number", "INCI Name"), index=0, key="search_mode") + input = st.text_input("Enter input:", "") if input: st.caption(f"Ricerca per {input}: trovati i seguenti ingredienti.") - results = search_cas_number(input) + if type == "CAS Number": + results = search_cas_inci(input, type='cas') + else: + results = search_cas_inci(input, type='inci') if results: # Crea le stringhe per la selectbox: "CAS - INCI" @@ -64,14 +69,20 @@ def home(): # Salva solo il CAS selezionato nel session_state (estrae la parte prima del " - ") if selected_display and selected_display != "": selected_cas = selected_display.split(" - ")[0] + if ";" in selected_cas: + selected_cas = st.selectbox(options=selected_cas.split(";"), label="Multiple CAS found, please select one:") + elif "/" in selected_cas: + selected_cas = st.selectbox(options=selected_cas.split("/"), label="Multiple CAS found, please select one:") st.session_state.selected_cas = selected_cas st.success(f"CAS Number selezionato: {selected_cas}") else: # Nessun risultato trovato: permetti di usare l'input manuale st.warning("Nessun risultato trovato nel database.") - if st.button("Usa questo CAS Number"): + if st.button("Usa questo CAS Number") and type == "CAS Number": st.session_state.selected_cas = input st.success(f"CAS Number salvato: {input}") + else: + st.info("INCI non trovato, scegli per CAS o modifica l'input.") # Mostra il CAS attualmente selezionato if st.session_state.selected_cas: @@ -81,13 +92,14 @@ def home(): home_page = st.Page(home, title="Home", icon="๐Ÿ ", default=True) echa_page = st.Page("pages/echa.py", title="ECHA Database", icon="๐Ÿงช") cosing_page = st.Page("pages/cosing.py", title="CosIng", icon="๐Ÿ’„") +dap_page = st.Page("pages/dap.py", title="DAP", icon="๐Ÿงฌ") #pubchem_page = st.Page("pages/pubchem.py", title="PubChem", icon="๐Ÿงฌ") #cir_page = st.Page("pages/cir.py", title="CIR", icon="๐Ÿ“Š") pg = st.navigation({ "Ricerca": [home_page], - "Database": [echa_page, cosing_page] + "Database": [echa_page, cosing_page, dap_page] }) pg.run() \ No newline at end of file diff --git a/functions.py b/functions.py index b5fc3c1..7c4c3c9 100644 --- a/functions.py +++ b/functions.py @@ -29,14 +29,20 @@ def cosing_request(cas_num: str) -> Dict[str, Any]: def generate_pdf_download(cas, origin, link): url = 'https://api.cosmoguard.it/api/v1/common/generate-pdf' name = f'{cas}_{origin}' - response = requests.post( - url, - json = { - 'link': link, - 'name': name + if link is not None: + response = requests.post( + url, + json = { + 'link': link, + 'name': name + } + ) + data = response.json() + else: + data = { + 'success': False, + 'error': 'No dossier exists for this origin.' } - ) - data = response.json() if data['success'] == True: url = f'https://api.cosmoguard.it/api/v1/common/download-pdf/{name}' response = requests.get(url) diff --git a/functions_ui.py b/functions_ui.py index 7f03a19..a90143d 100644 --- a/functions_ui.py +++ b/functions_ui.py @@ -14,11 +14,13 @@ def open_csv_file(file_path): con.execute(query) return con -def search_cas_number(cas_number, type = 'cas'): +def search_cas_inci(input, type = 'cas'): """Cerca un numero CAS nei dati forniti e restituisce CAS e INCI.""" con = open_csv_file('data.csv') - - query = f"SELECT * FROM index WHERE casNo LIKE '%{cas_number}%'" + if type == 'cas': + query = f"SELECT * FROM index WHERE casNo LIKE '%{input}%'" + else: + query = f"SELECT * FROM index WHERE inciName ILIKE '%{input}%'" results = con.execute(query).fetchdf() # Restituisce una lista di tuple (casNo, inciName) @@ -45,5 +47,5 @@ def download_pdf(casNo, origin, link): ) if __name__ == "__main__": - data = search_cas_number('102242-62-6') + data = search_cas_inci('102242-62-6') print(data) \ No newline at end of file diff --git a/pages/dap.py b/pages/dap.py new file mode 100644 index 0000000..3ae47bf --- /dev/null +++ b/pages/dap.py @@ -0,0 +1,121 @@ +import streamlit as st +import requests +import json + +st.title("PubChem Data Viewer") + +if st.session_state.get('selected_cas', None) is None: + st.warning("Nessun CAS Number selezionato. Torna alla pagina principale per effettuare una ricerca.") + st.stop() +else: + cas_number = st.session_state.selected_cas + +# Make API request +with st.spinner("Fetching data from PubChem..."): + try: + response = requests.post( + "https://api.cosmoguard.it/api/v1/common/pubchem", + json={"cas": cas_number} + ) + response.raise_for_status() + result = response.json() + except requests.exceptions.RequestException as e: + st.error(f"Error fetching data: {e}") + st.stop() + +# Check if request was successful +if not result.get("success", False): + st.error(f"API Error: {result.get('error', 'Unknown error')}") + st.stop() + +data = result.get("data", {}) + +# Display substance header +st.subheader(f"{data.get('first_pubchem_name', 'Unknown').title()}") + +# Basic info container +with st.container(border=True): + col1, col2, col3 = st.columns(3) + with col1: + st.caption("CAS Number") + st.write(data.get("CAS", "โ€”")) + with col2: + st.caption("PubChem CID") + st.write(data.get("CID", "โ€”")) + with col3: + if data.get("pubchem_link"): + st.link_button("View on PubChem", data.get("pubchem_link")) + +st.divider() + +# Physical/Chemical Properties +st.subheader("Physical & Chemical Properties") + +with st.container(border=True): + prop_col1, prop_col2, prop_col3, prop_col4 = st.columns(4) + + with prop_col1: + st.metric("Molecular Weight", f"{data.get('MolecularWeight', 'โ€”')} g/mol" if data.get('MolecularWeight') else "โ€”") + + with prop_col2: + st.metric("XLogP", data.get('XLogP', 'โ€”')) + + with prop_col3: + st.metric("Exact Mass", data.get('ExactMass', 'โ€”')) + + with prop_col4: + st.metric("TPSA", f"{data.get('TPSA', 'โ€”')} ลฒ" if data.get('TPSA') else "โ€”") + +st.divider() + +# Melting Point +melting_points = data.get("Melting Point", []) +if melting_points: + st.subheader("Melting Point") + + with st.expander(f"View {len(melting_points)} reference(s)", expanded=True): + for idx, mp in enumerate(melting_points): + with st.container(border=True): + st.markdown(f"**Reference {idx + 1}**") + + if mp.get("Value"): + st.info(mp.get("Value")) + + if mp.get("Reference"): + st.caption(f"๐Ÿ“š {mp.get('Reference')}") + + if mp.get("Description"): + st.caption(f"โ„น๏ธ {mp.get('Description')}") + + if mp.get("ReferenceNumber"): + st.caption(f"Ref #: {mp.get('ReferenceNumber')}") + +# Dissociation Constants +dissociation_constants = data.get("Dissociation Constants", []) +if dissociation_constants: + st.divider() + st.subheader("Dissociation Constants (pKa)") + + with st.expander(f"View {len(dissociation_constants)} reference(s)", expanded=True): + for idx, dc in enumerate(dissociation_constants): + with st.container(border=True): + st.markdown(f"**Reference {idx + 1}**") + + if dc.get("Value"): + # Check if it's a dictionary or string + value = dc.get("Value") + if isinstance(value, dict): + st.code(json.dumps(value, indent=2)) + else: + st.info(value) + + if dc.get("Reference"): + st.caption(f"๐Ÿ“š {dc.get('Reference')}") + + if dc.get("ReferenceNumber"): + st.caption(f"Ref #: {dc.get('ReferenceNumber')}") + +# Raw JSON viewer +st.divider() +with st.expander("View Raw JSON Response"): + st.json(result)