diff --git a/docs/logiche.md b/docs/logiche.md new file mode 100644 index 0000000..eaf5b46 --- /dev/null +++ b/docs/logiche.md @@ -0,0 +1,62 @@ +1) + +dati lista ingrediente: +- informazioni anagrafiche +- tipo > automatica associazione a esposizione, se non c'è ritorna errore +- associazione cas-inci, identificazione AQUA +- aggiungere 5 cifre decimali nelle percentuali +- CAS multipli vanno spacchettati in mini loop + +va separato input da dict ingredients + +Se informazioni anagrafiche hanno senso (validatore esiste, tipo cosmetico esiste) > aggiungi a Mongo. + +Viene arricchito subito con informazioni da Cosing, aggiunte chiavi: +- INCI +- Tox : {NOAEL: (val, fonte), LD50, LOAEL} +- Tox Resources +- CosIng: Restrizioni, Uso : lista, Sostanze identificate +- DAP {} +- Esposizione +- Riassunto, completo si/no +- Stato + +Funzione che va a verificare se tutto queste siano complete anche solo parzialmente per ogni ingrediente, viene fatto un riassunto dei dati trovati + +2) + +generazione excel partendo da questo dato + +Processo: +1. +- Input arriva grezzo +- va caricato su mongodb, restituisce _id +Trovo ID delle info anagrafiche: + - Cliente + - Compilatore + - Tipo +- Creo un file progetto, restituisce _id +Inserisco il record su DB + +-- STATO 0 -- + +2. +Faccio una verifica per vedere quanti dati pronti per essere elaborati +prendo il più vecchio + +L'entità ha l'ordine e il progetto, recupero i due file + +1. Va a cercare su CosIng + - Match relativo INCI + - Prende Restrizioni, Uso, Sostanze identificate +4. Calcolo SED +2. Va a pescare Dati DAP +5. Calcolo DAP +3. Va a cercare Echa + - orchestrator echa + - Pulizia e ricerca dei dati essenziali (NOAEL e link) + +Per ognuno orchestrator > pulizia > identifico NOAEL + + + diff --git a/main.db b/main.db new file mode 100644 index 0000000..88ec05a Binary files /dev/null and b/main.db differ diff --git a/main.db.wal b/main.db.wal new file mode 100644 index 0000000..b718995 Binary files /dev/null and b/main.db.wal differ diff --git a/marimo/database_creation.py b/marimo/database_creation.py new file mode 100644 index 0000000..4b8797f --- /dev/null +++ b/marimo/database_creation.py @@ -0,0 +1,158 @@ +import marimo + +__generated_with = "0.16.5" +app = marimo.App(width="medium") + + +@app.cell +def _(): + import marimo as mo + import duckdb + return duckdb, mo + + +@app.cell +def _(duckdb): + con = duckdb.connect('main.db') + return (con,) + + +@app.cell +def _(con, mo): + _df = mo.sql( + f""" + --CREATE SEQUENCE seq_clienti START 1; + --CREATE SEQUENCE seq_compilatori START 1; + --CREATE SEQUENCE seq_tipi_prodotti START 1; + --CREATE SEQUENCE seq_stati_ordini START 1; + --CREATE SEQUENCE seq_ordini START 1; + """, + engine=con + ) + return + + +@app.cell +def _(con, mo): + _df = mo.sql( + f""" + CREATE OR REPLACE TABLE clienti ( + nome_cliente VARCHAR UNIQUE, + id_cliente INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq_clienti') + ) + """, + engine=con + ) + return + + +@app.cell +def _(con, mo): + _df = mo.sql( + f""" + CREATE OR REPLACE TABLE compilatori ( + nome_compilatore VARCHAR UNIQUE, + id_compilatore INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq_compilatori') + ) + """, + engine=con + ) + return + + +@app.cell +def _(con, mo): + _df = mo.sql( + f""" + + CREATE OR REPLACE TABLE tipi_prodotti ( + nome_tipo VARCHAR UNIQUE, + id_tipo INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq_tipi_prodotti'), + luogo_applicazione VARCHAR, + espo_primaria VARCHAR, + espo_secondaria VARCHAR, + espo_nano VARCHAR, + supericie_cm2 INT, + frequenza INT, + qty_daily_stimata INT, + qty_daily_relativa INT, + ritenzione FLOAT, + espo_daily_calcolata INT, + espo_daily_relativa_calcolata INT, + peso INT, + target VARCHAR + ) + """, + engine=con + ) + return + + +@app.cell +def _(con, mo): + _df = mo.sql( + f""" + + CREATE OR REPLACE TABLE stati_ordini ( + id_stato INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq_stati_ordini'), + nome_stato VARCHAR + ) + """, + engine=con + ) + return (stati_ordini,) + + +@app.cell +def _(con, mo): + _df = mo.sql( + f""" + + CREATE OR REPLACE TABLE ordini ( + id_ordine INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq_ordini'), + id_cliente INTEGER, + id_compilatore INTEGER, + id_tipo_prodotto INTEGER, + uuid_ordine VARCHAR NOT NULL, + uuid_progetto VARCHAR, + data_ordine DATETIME NOT NULL, + stato_ordine INTEGER DEFAULT 0, + note VARCHAR, + FOREIGN KEY (id_cliente) REFERENCES clienti(id_cliente), + FOREIGN KEY (id_compilatore) REFERENCES compilatori(id_compilatore), + FOREIGN KEY (id_tipo_prodotto) REFERENCES tipi_prodotti(id_tipo), + FOREIGN KEY (stato_ordine) REFERENCES stati_ordini(id_stato) + ) + """, + engine=con + ) + return + + +@app.cell +def _(con, mo): + _df = mo.sql( + f""" + + """, + engine=con + ) + return + + +@app.cell +def _(con, mo, stati_ordini): + _df = mo.sql( + f""" + INSERT INTO stati_ordini (nome_stato) VALUES ( + 'Ordine registrato', + '' + ) + """, + engine=con + ) + return + + +if __name__ == "__main__": + app.run() diff --git a/debug.py b/marimo/debug.py similarity index 98% rename from debug.py rename to marimo/debug.py index 39a4f1f..31a9187 100644 --- a/debug.py +++ b/marimo/debug.py @@ -18,7 +18,7 @@ def _(): @app.cell def _(): - cas = '102-71-6' + cas = '63148-62-9' return (cas,) diff --git a/marimo/debug_cosing.py b/marimo/debug_cosing.py new file mode 100644 index 0000000..1145640 --- /dev/null +++ b/marimo/debug_cosing.py @@ -0,0 +1,32 @@ +import marimo + +__generated_with = "0.16.5" +app = marimo.App(width="medium") + + +@app.cell +def _(): + import marimo as mo + return + + +@app.cell +def _(): + from pif_compiler.services.srv_cosing import cosing_search + return (cosing_search,) + + +@app.cell +def _(): + cas = ' 9006-65-9 ' + return (cas,) + + +@app.cell +def _(cas, cosing_search): + cosing_search(cas, mode='cas') + return + + +if __name__ == "__main__": + app.run() diff --git a/debug_echa_find.py b/marimo/debug_echa_find.py similarity index 100% rename from debug_echa_find.py rename to marimo/debug_echa_find.py diff --git a/src/pif_compiler/api/routes/common.py b/src/pif_compiler/api/routes/common.py index 5c32a47..a7d8b1a 100644 --- a/src/pif_compiler/api/routes/common.py +++ b/src/pif_compiler/api/routes/common.py @@ -6,6 +6,7 @@ import os from pif_compiler.functions.common_func import generate_pdf from pif_compiler.services.srv_pubchem import pubchem_dap +from pif_compiler.services.srv_cir import search_ingredient from pif_compiler.functions.common_log import get_logger logger = get_logger() @@ -203,6 +204,71 @@ async def search_pubchem(request: PubchemRequest): ) +class CirSearchRequest(BaseModel): + text: str = Field(..., description="Text to search for in the CIR database") + + class Config: + json_schema_extra = { + "example": { + "text": "olio di argan" + } + } + + +class CirSearchResponse(BaseModel): + success: bool + text: str + results: Optional[list] = None + count: Optional[int] = None + error: Optional[str] = None + + +@router.post("/common/cir-search", response_model=CirSearchResponse, tags=["Common"]) +async def cir_search_endpoint(request: CirSearchRequest): + """ + Search for ingredients in the CIR (Cosmetic Ingredient Review) database. + + This endpoint searches the CIR NOAEL database for ingredients matching + the provided text query. + + Args: + request: CirSearchRequest containing the search text + + Returns: + CirSearchResponse with the search results or error information + """ + logger.info(f"API request received for CIR search: text='{request.text}'") + + try: + results = search_ingredient(request.text) + + if results is None: + logger.error(f"CIR search returned None for text: {request.text}") + return CirSearchResponse( + success=False, + text=request.text, + results=None, + count=0, + error="An error occurred while searching the CIR database. Please check the logs for details." + ) + + logger.info(f"Successfully retrieved {len(results)} results from CIR database for text: {request.text}") + return CirSearchResponse( + success=True, + text=request.text, + results=results, + count=len(results), + error=None + ) + + except Exception as e: + logger.error(f"Error processing CIR search request for text '{request.text}': {str(e)}", exc_info=True) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Internal error while processing CIR search request: {str(e)}" + ) + + @router.get("/common/health", tags=["Common"]) async def common_health_check(): """ @@ -217,6 +283,10 @@ async def common_health_check(): "api": "operational", "logging": "operational", "utilities": "operational", - "pubchem": "operational" + "pubchem": "operational", + "cir": "operational" } } + + + diff --git a/src/pif_compiler/functions/common_func.py b/src/pif_compiler/functions/common_func.py index 0145e4e..24aac2f 100644 --- a/src/pif_compiler/functions/common_func.py +++ b/src/pif_compiler/functions/common_func.py @@ -1,8 +1,11 @@ from playwright.async_api import async_playwright import os +from pymongo import MongoClient + from pif_compiler.functions.common_log import get_logger + log = get_logger() async def generate_pdf(link: str, name: str): @@ -89,4 +92,8 @@ async def generate_pdf(link: str, name: str): except Exception as e: log.error(f"Error generating PDF for {name}: {str(e)}", exc_info=True) - return False \ No newline at end of file + return False + + + + \ No newline at end of file diff --git a/src/pif_compiler/functions/orders.py b/src/pif_compiler/functions/orders.py new file mode 100644 index 0000000..68b3969 --- /dev/null +++ b/src/pif_compiler/functions/orders.py @@ -0,0 +1,6 @@ +from pymongo import MongoClient + +from pif_compiler.functions.common_log import get_logger +from pif_compiler.functions.db_utils import db_connect + +log = get_logger() \ No newline at end of file diff --git a/src/pif_compiler/services/srv_cir.py b/src/pif_compiler/services/srv_cir.py new file mode 100644 index 0000000..f7dbdc8 --- /dev/null +++ b/src/pif_compiler/services/srv_cir.py @@ -0,0 +1,14 @@ +from pif_compiler.functions.common_log import get_logger +from pif_compiler.functions.db_utils import db_connect + +log = get_logger() + +def search_ingredient(text): + col = db_connect(db_name="cir", collection_name="noael") + col.create_index([("ingrediente", "text")]) + log.info(f"Searching for ingredient in CIR database: {text}") + risultati = col.find({ "$text": { "$search": text } }) + return list(risultati) + + +