Merge branch 'main' of github.com:adish-rmr/cosmoguard_frontend
This commit is contained in:
commit
c3e61894b0
4 changed files with 186 additions and 17 deletions
52
app.py
52
app.py
|
|
@ -1,6 +1,6 @@
|
||||||
import streamlit as st
|
import streamlit as st
|
||||||
|
|
||||||
from functions_ui import search_cas_number
|
from functions_ui import search_cas_inci
|
||||||
|
|
||||||
# Configure page
|
# Configure page
|
||||||
st.set_page_config(
|
st.set_page_config(
|
||||||
|
|
@ -48,11 +48,16 @@ def home():
|
||||||
# Inizializza session_state per il CAS number se non esiste
|
# Inizializza session_state per il CAS number se non esiste
|
||||||
if 'selected_cas' not in st.session_state:
|
if 'selected_cas' not in st.session_state:
|
||||||
st.session_state.selected_cas = None
|
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:
|
if input:
|
||||||
st.caption(f"Ricerca per {input}: trovati i seguenti ingredienti.")
|
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:
|
if results:
|
||||||
# Crea le stringhe per la selectbox: "CAS - INCI"
|
# Crea le stringhe per la selectbox: "CAS - INCI"
|
||||||
|
|
@ -64,30 +69,65 @@ def home():
|
||||||
# Salva solo il CAS selezionato nel session_state (estrae la parte prima del " - ")
|
# Salva solo il CAS selezionato nel session_state (estrae la parte prima del " - ")
|
||||||
if selected_display and selected_display != "":
|
if selected_display and selected_display != "":
|
||||||
selected_cas = selected_display.split(" - ")[0]
|
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.session_state.selected_cas = selected_cas
|
||||||
st.success(f"CAS Number selezionato: {selected_cas}")
|
st.success(f"CAS Number selezionato: {selected_cas}")
|
||||||
else:
|
else:
|
||||||
# Nessun risultato trovato: permetti di usare l'input manuale
|
# Nessun risultato trovato: permetti di usare l'input manuale
|
||||||
st.warning("Nessun risultato trovato nel database.")
|
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.session_state.selected_cas = input
|
||||||
st.success(f"CAS Number salvato: {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
|
# Mostra il CAS attualmente selezionato
|
||||||
if st.session_state.selected_cas:
|
if st.session_state.selected_cas:
|
||||||
st.info(f"CAS Number corrente: {st.session_state.selected_cas}")
|
st.info(f"CAS Number corrente: {st.session_state.selected_cas}")
|
||||||
|
|
||||||
|
# Changelog section
|
||||||
|
st.divider()
|
||||||
|
with st.expander("📝 Registro degli aggiornamenti"):
|
||||||
|
# Placeholder for future versions
|
||||||
|
st.markdown("""
|
||||||
|
### Versione 0.2.0 | 2026-01-15
|
||||||
|
- Aggiunta ricerca per nome INCI
|
||||||
|
- Possibilità di filtrare per singoli CAS in caso di multipli per stesso INCI
|
||||||
|
- Verifica se il link al download esiste prima di generare il PDF
|
||||||
|
- Aggiunta pagina per verificare i valori per determinare il DAP (da PubChem)
|
||||||
|
- La ricerca per ingrediente su ECHA non va più in errore se almeno uno dei tre dossier esiste
|
||||||
|
- Filtrati i dossier ECHA se sono di tipo 'full' e sono di tipo 'Lead' (sempre Active)
|
||||||
|
---
|
||||||
|
""")
|
||||||
|
|
||||||
|
st.markdown("""
|
||||||
|
### Versione 0.1.0 | 2025-12-18
|
||||||
|
- Release iniziale
|
||||||
|
- Funzionalità di ricerca per Numero CAS
|
||||||
|
- Integrazione con ECHA
|
||||||
|
- Integrazione con CosIng
|
||||||
|
- Protezione con password
|
||||||
|
- Sistema di navigazione multi-pagina
|
||||||
|
- Download del PDF ECHA dossier
|
||||||
|
- Visualizzazione dati tossicologici ECHA e CosIng
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
# Navigation
|
# Navigation
|
||||||
home_page = st.Page(home, title="Home", icon="🏠", default=True)
|
home_page = st.Page(home, title="Home", icon="🏠", default=True)
|
||||||
echa_page = st.Page("pages/echa.py", title="ECHA Database", icon="🧪")
|
echa_page = st.Page("pages/echa.py", title="ECHA Database", icon="🧪")
|
||||||
cosing_page = st.Page("pages/cosing.py", title="CosIng", 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="🧬")
|
#pubchem_page = st.Page("pages/pubchem.py", title="PubChem", icon="🧬")
|
||||||
#cir_page = st.Page("pages/cir.py", title="CIR", icon="📊")
|
#cir_page = st.Page("pages/cir.py", title="CIR", icon="📊")
|
||||||
|
|
||||||
|
|
||||||
pg = st.navigation({
|
pg = st.navigation({
|
||||||
"Ricerca": [home_page],
|
"Ricerca": [home_page],
|
||||||
"Database": [echa_page, cosing_page]
|
"Database": [echa_page, cosing_page, dap_page]
|
||||||
})
|
})
|
||||||
|
|
||||||
pg.run()
|
pg.run()
|
||||||
20
functions.py
20
functions.py
|
|
@ -29,14 +29,20 @@ def cosing_request(cas_num: str) -> Dict[str, Any]:
|
||||||
def generate_pdf_download(cas, origin, link):
|
def generate_pdf_download(cas, origin, link):
|
||||||
url = 'https://api.cosmoguard.it/api/v1/common/generate-pdf'
|
url = 'https://api.cosmoguard.it/api/v1/common/generate-pdf'
|
||||||
name = f'{cas}_{origin}'
|
name = f'{cas}_{origin}'
|
||||||
response = requests.post(
|
if link is not None:
|
||||||
url,
|
response = requests.post(
|
||||||
json = {
|
url,
|
||||||
'link': link,
|
json = {
|
||||||
'name': name
|
'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:
|
if data['success'] == True:
|
||||||
url = f'https://api.cosmoguard.it/api/v1/common/download-pdf/{name}'
|
url = f'https://api.cosmoguard.it/api/v1/common/download-pdf/{name}'
|
||||||
response = requests.get(url)
|
response = requests.get(url)
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,13 @@ def open_csv_file(file_path):
|
||||||
con.execute(query)
|
con.execute(query)
|
||||||
return con
|
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."""
|
"""Cerca un numero CAS nei dati forniti e restituisce CAS e INCI."""
|
||||||
con = open_csv_file('data.csv')
|
con = open_csv_file('data.csv')
|
||||||
|
if type == 'cas':
|
||||||
query = f"SELECT * FROM index WHERE casNo LIKE '%{cas_number}%'"
|
query = f"SELECT * FROM index WHERE casNo LIKE '%{input}%'"
|
||||||
|
else:
|
||||||
|
query = f"SELECT * FROM index WHERE inciName ILIKE '%{input}%'"
|
||||||
results = con.execute(query).fetchdf()
|
results = con.execute(query).fetchdf()
|
||||||
|
|
||||||
# Restituisce una lista di tuple (casNo, inciName)
|
# Restituisce una lista di tuple (casNo, inciName)
|
||||||
|
|
@ -45,5 +47,5 @@ def download_pdf(casNo, origin, link):
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
data = search_cas_number('102242-62-6')
|
data = search_cas_inci('102242-62-6')
|
||||||
print(data)
|
print(data)
|
||||||
121
pages/dap.py
Normal file
121
pages/dap.py
Normal file
|
|
@ -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)
|
||||||
Loading…
Reference in a new issue