Update app.py
Browse files
app.py
CHANGED
|
@@ -16,7 +16,7 @@ logging.basicConfig(
|
|
| 16 |
handlers=[logging.FileHandler("app.log"), logging.StreamHandler()]
|
| 17 |
)
|
| 18 |
logger = logging.getLogger(__name__)
|
| 19 |
-
|
| 20 |
# ---------------------------------------------------------------------------
|
| 21 |
# COSTANTI / CHIAVI / MODELLI
|
| 22 |
# ---------------------------------------------------------------------------
|
|
@@ -214,27 +214,22 @@ def classify_and_translate(question_text: str, model_answer_text: str):
|
|
| 214 |
try:
|
| 215 |
question_lang_result = lang_detect_client.text_classification(text=question_text)
|
| 216 |
question_lang = question_lang_result[0]['label']
|
| 217 |
-
explanation_dict['language_detection'] = f"Domanda in: {question_lang}."
|
| 218 |
logger.info(f"[LangDetect] Lingua della domanda: {question_lang}")
|
| 219 |
except Exception as e:
|
| 220 |
logger.error(f"Errore nel rilevamento della lingua della domanda: {e}")
|
| 221 |
question_lang = "en" # Fallback se non riusciamo a rilevare la lingua
|
| 222 |
-
explanation_dict['language_detection'] = "Lingua domanda non rilevata, impostata a 'en'."
|
| 223 |
# Rileva la lingua della risposta
|
| 224 |
try:
|
| 225 |
answer_lang_result = lang_detect_client.text_classification(text=model_answer_text)
|
| 226 |
answer_lang = answer_lang_result[0]['label']
|
| 227 |
-
explanation_dict['language_detection'] += f" Risposta in: {answer_lang}."
|
| 228 |
logger.info(f"[LangDetect] Lingua della risposta: {answer_lang}")
|
| 229 |
except Exception as e:
|
| 230 |
logger.error(f"Errore nel rilevamento della lingua della risposta: {e}")
|
| 231 |
answer_lang = "it" # Fallback se non riusciamo a rilevare la lingua
|
| 232 |
-
explanation_dict['language_detection'] += " Lingua risposta non rilevata, impostata a 'it'."
|
| 233 |
|
| 234 |
# Se domanda e risposta sono nella stessa lingua, non traduciamo
|
| 235 |
if question_lang == answer_lang:
|
| 236 |
logger.info("[Translate] Nessuna traduzione necessaria: stessa lingua.")
|
| 237 |
-
explanation_dict['translation'] = "Nessuna traduzione necessaria."
|
| 238 |
return model_answer_text
|
| 239 |
|
| 240 |
# Altrimenti, costruiamo "al volo" il modello di traduzione appropriato
|
|
@@ -244,17 +239,13 @@ def classify_and_translate(question_text: str, model_answer_text: str):
|
|
| 244 |
token=HF_API_KEY,
|
| 245 |
model=translator_model
|
| 246 |
)
|
| 247 |
-
explanation_dict['translation'] = f"Usato modello: {translator_model}."
|
| 248 |
# Traduzione della risposta
|
| 249 |
try:
|
| 250 |
translation_result = translator_client.translation(text=model_answer_text)
|
| 251 |
translated_answer = translation_result["translation_text"]
|
| 252 |
-
explanation_dict['translation'] += " Traduzione riuscita."
|
| 253 |
except Exception as e:
|
| 254 |
logger.error(f"Errore nella traduzione {answer_lang} -> {question_lang}: {e}")
|
| 255 |
-
explanation_dict['translation'] += " Traduzione fallita, risposta originale usata."
|
| 256 |
# Se fallisce, restituiamo la risposta originale come fallback
|
| 257 |
-
explanation_dict['translation'] = "Errore inizializzazione traduttore."
|
| 258 |
translated_answer = model_answer_text
|
| 259 |
|
| 260 |
return translated_answer
|
|
@@ -357,7 +348,6 @@ def is_sparql_query_valid(query: str) -> bool:
|
|
| 357 |
# ---------------------------------------------------------------------------
|
| 358 |
@app.post("/assistant")
|
| 359 |
def assistant_endpoint(req: AssistantRequest):
|
| 360 |
-
explanation_dict = {}
|
| 361 |
"""
|
| 362 |
Endpoint che gestisce l'intera pipeline:
|
| 363 |
1) Genera una query SPARQL dal messaggio dell'utente (prompt dedicato).
|
|
@@ -391,19 +381,15 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 391 |
# Serializziamo l'ontologia in XML per fornirla al prompt (anche se si chiama 'turtle' va bene così).
|
| 392 |
ontology_turtle = ontology_graph.serialize(format="xml")
|
| 393 |
logger.debug("Ontologia serializzata con successo (XML).")
|
| 394 |
-
explanation_dict['ontology'] = "Ontologia serializzata."
|
| 395 |
except Exception as e:
|
| 396 |
logger.warning(f"Impossibile serializzare l'ontologia in formato XML: {e}")
|
| 397 |
-
explanation_dict['ontology'] = f"Errore serializzazione: {e}."
|
| 398 |
ontology_turtle = ""
|
| 399 |
|
| 400 |
# Creiamo il prompt di sistema per la generazione SPARQL
|
| 401 |
system_prompt_sparql = create_system_prompt_for_sparql(ontology_turtle)
|
| 402 |
-
explanation_dict['sparql_prompt'] = "Prompt SPARQL creato."
|
| 403 |
# Chiamata al modello per generare la query SPARQL
|
| 404 |
try:
|
| 405 |
logger.debug("[assistant_endpoint] Chiamata HF per generare la query SPARQL...")
|
| 406 |
-
explanation_dict['sparql_generation'] = "Generazione query SPARQL iniziata."
|
| 407 |
gen_sparql_output = hf_generation_client.chat.completions.create(
|
| 408 |
messages=[
|
| 409 |
{"role": "system", "content": system_prompt_sparql},
|
|
@@ -414,10 +400,8 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 414 |
)
|
| 415 |
possible_query = gen_sparql_output["choices"][0]["message"]["content"].strip()
|
| 416 |
logger.info(f"[assistant_endpoint] Query generata dal modello: {possible_query}")
|
| 417 |
-
explanation_dict['sparql_generation'] += f" Query: {possible_query}."
|
| 418 |
except Exception as ex:
|
| 419 |
logger.error(f"Errore nella generazione della query SPARQL: {ex}")
|
| 420 |
-
explanation_dict['sparql_generation'] = f"Errore generazione SPARQL: {ex}."
|
| 421 |
# Se fallisce la generazione, consideriamo la query come "NO_SPARQL"
|
| 422 |
possible_query = "NO_SPARQL"
|
| 423 |
|
|
@@ -428,15 +412,12 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 428 |
else:
|
| 429 |
# Applichiamo la correzione avanzata
|
| 430 |
advanced_corrected = correct_sparql_syntax_advanced(possible_query)
|
| 431 |
-
explanation_dict['sparql_correction'] = "Sintassi SPARQL corretta."
|
| 432 |
# Verifichiamo la validità della query
|
| 433 |
if is_sparql_query_valid(advanced_corrected):
|
| 434 |
generated_query = advanced_corrected
|
| 435 |
logger.debug(f"[assistant_endpoint] Query SPARQL valida dopo correzione avanzata: {generated_query}")
|
| 436 |
-
explanation_dict['sparql_validation'] = "Query SPARQL valida."
|
| 437 |
else:
|
| 438 |
logger.debug("[assistant_endpoint] Query SPARQL non valida. Verrà ignorata.")
|
| 439 |
-
explanation_dict['sparql_validation'] = "Query SPARQL non valida."
|
| 440 |
generated_query = None
|
| 441 |
|
| 442 |
# -----------------------------------------------------------------------
|
|
@@ -446,23 +427,17 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 446 |
point = "" # variabile per contenere il punto (inizialmente nessuno)
|
| 447 |
if generated_query:
|
| 448 |
logger.debug(f"[assistant_endpoint] Esecuzione della query SPARQL:\n{generated_query}")
|
| 449 |
-
explanation_dict['sparql_execution'] = "Esecuzione query SPARQL."
|
| 450 |
try:
|
| 451 |
query_result = ontology_graph.query(generated_query)
|
| 452 |
results = list(query_result)
|
| 453 |
logger.info(f"[assistant_endpoint] Query eseguita con successo. Numero risultati = {len(results)}")
|
| 454 |
-
explanation_dict['sparql_execution'] += f" Risultati: {len(results)}."
|
| 455 |
except Exception as ex:
|
| 456 |
logger.error(f"[assistant_endpoint] Errore nell'esecuzione della query: {ex}")
|
| 457 |
-
explanation_dict['sparql_execution'] = f"Errore esecuzione: {ex}."
|
| 458 |
results = []
|
| 459 |
-
else:
|
| 460 |
-
explanation_dict['sparql_execution'] = "Nessuna query eseguita."
|
| 461 |
# -----------------------------------------------------------------------
|
| 462 |
# STEP 3: Generazione della risposta finale stile "guida museale"
|
| 463 |
# -----------------------------------------------------------------------
|
| 464 |
system_prompt_guide = create_system_prompt_for_guide()
|
| 465 |
-
explanation_dict['guide_prompt'] = "Prompt guida museale creato."
|
| 466 |
if generated_query and results:
|
| 467 |
# Caso: query generata + risultati SPARQL
|
| 468 |
# Convertiamo i risultati in una stringa più leggibile
|
|
@@ -488,7 +463,6 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 488 |
"Rispondi in modo breve (max ~50 parole)."
|
| 489 |
)
|
| 490 |
logger.debug("[assistant_endpoint] Prompt di risposta con risultati SPARQL.")
|
| 491 |
-
explanation_dict['guide_prompt'] += " Inclusi risultati SPARQL."
|
| 492 |
elif generated_query and not results:
|
| 493 |
# Caso: query valida ma 0 risultati
|
| 494 |
second_prompt = (
|
|
@@ -498,7 +472,6 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 498 |
"Nessun risultato dalla query. Prova comunque a rispondere con le tue conoscenze."
|
| 499 |
)
|
| 500 |
logger.debug("[assistant_endpoint] Prompt di risposta: query valida ma senza risultati.")
|
| 501 |
-
explanation_dict['guide_prompt'] += " Query valida senza risultati."
|
| 502 |
else:
|
| 503 |
# Caso: nessuna query generata
|
| 504 |
second_prompt = (
|
|
@@ -507,11 +480,9 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 507 |
"Nessuna query SPARQL generata. Rispondi come puoi, riarrangiando le tue conoscenze."
|
| 508 |
)
|
| 509 |
logger.debug("[assistant_endpoint] Prompt di risposta: nessuna query generata.")
|
| 510 |
-
explanation_dict['guide_prompt'] += " Nessuna query generata."
|
| 511 |
# Chiamata finale al modello per la risposta "guida museale"
|
| 512 |
try:
|
| 513 |
logger.debug("[assistant_endpoint] Chiamata HF per generare la risposta finale...")
|
| 514 |
-
explanation_dict['response_generation'] = "Generazione risposta finale iniziata."
|
| 515 |
final_output = hf_generation_client.chat.completions.create(
|
| 516 |
messages=[
|
| 517 |
{"role": "system", "content": second_prompt},
|
|
@@ -522,10 +493,8 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 522 |
)
|
| 523 |
final_answer = final_output["choices"][0]["message"]["content"].strip()
|
| 524 |
logger.info(f"[assistant_endpoint] Risposta finale generata: {final_answer}")
|
| 525 |
-
explanation_dict['response_generation'] += " Risposta generata."
|
| 526 |
except Exception as ex:
|
| 527 |
logger.error(f"Errore nella generazione della risposta finale: {ex}")
|
| 528 |
-
explanation_dict['response_generation'] = f"Errore generazione risposta finale: {ex}."
|
| 529 |
raise HTTPException(status_code=500, detail="Errore nella generazione della risposta in linguaggio naturale.")
|
| 530 |
|
| 531 |
# -----------------------------------------------------------------------
|
|
@@ -533,7 +502,6 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 533 |
# -----------------------------------------------------------------------
|
| 534 |
final_ans = classify_and_translate(user_message, final_answer)
|
| 535 |
final_ans = final_ans.replace('\\"', "").replace('\"', "")
|
| 536 |
-
explanation_dict['translation_completion'] = "Traduzione completata."
|
| 537 |
# -----------------------------------------------------------------------
|
| 538 |
# Restituzione in formato JSON
|
| 539 |
# -----------------------------------------------------------------------
|
|
@@ -541,7 +509,6 @@ def assistant_endpoint(req: AssistantRequest):
|
|
| 541 |
return {
|
| 542 |
"query": generated_query,
|
| 543 |
"response": final_ans,
|
| 544 |
-
"explanation": explanation_dict,
|
| 545 |
"point": point
|
| 546 |
}
|
| 547 |
# ---------------------------------------------------------------------------
|
|
|
|
| 16 |
handlers=[logging.FileHandler("app.log"), logging.StreamHandler()]
|
| 17 |
)
|
| 18 |
logger = logging.getLogger(__name__)
|
| 19 |
+
|
| 20 |
# ---------------------------------------------------------------------------
|
| 21 |
# COSTANTI / CHIAVI / MODELLI
|
| 22 |
# ---------------------------------------------------------------------------
|
|
|
|
| 214 |
try:
|
| 215 |
question_lang_result = lang_detect_client.text_classification(text=question_text)
|
| 216 |
question_lang = question_lang_result[0]['label']
|
|
|
|
| 217 |
logger.info(f"[LangDetect] Lingua della domanda: {question_lang}")
|
| 218 |
except Exception as e:
|
| 219 |
logger.error(f"Errore nel rilevamento della lingua della domanda: {e}")
|
| 220 |
question_lang = "en" # Fallback se non riusciamo a rilevare la lingua
|
|
|
|
| 221 |
# Rileva la lingua della risposta
|
| 222 |
try:
|
| 223 |
answer_lang_result = lang_detect_client.text_classification(text=model_answer_text)
|
| 224 |
answer_lang = answer_lang_result[0]['label']
|
|
|
|
| 225 |
logger.info(f"[LangDetect] Lingua della risposta: {answer_lang}")
|
| 226 |
except Exception as e:
|
| 227 |
logger.error(f"Errore nel rilevamento della lingua della risposta: {e}")
|
| 228 |
answer_lang = "it" # Fallback se non riusciamo a rilevare la lingua
|
|
|
|
| 229 |
|
| 230 |
# Se domanda e risposta sono nella stessa lingua, non traduciamo
|
| 231 |
if question_lang == answer_lang:
|
| 232 |
logger.info("[Translate] Nessuna traduzione necessaria: stessa lingua.")
|
|
|
|
| 233 |
return model_answer_text
|
| 234 |
|
| 235 |
# Altrimenti, costruiamo "al volo" il modello di traduzione appropriato
|
|
|
|
| 239 |
token=HF_API_KEY,
|
| 240 |
model=translator_model
|
| 241 |
)
|
|
|
|
| 242 |
# Traduzione della risposta
|
| 243 |
try:
|
| 244 |
translation_result = translator_client.translation(text=model_answer_text)
|
| 245 |
translated_answer = translation_result["translation_text"]
|
|
|
|
| 246 |
except Exception as e:
|
| 247 |
logger.error(f"Errore nella traduzione {answer_lang} -> {question_lang}: {e}")
|
|
|
|
| 248 |
# Se fallisce, restituiamo la risposta originale come fallback
|
|
|
|
| 249 |
translated_answer = model_answer_text
|
| 250 |
|
| 251 |
return translated_answer
|
|
|
|
| 348 |
# ---------------------------------------------------------------------------
|
| 349 |
@app.post("/assistant")
|
| 350 |
def assistant_endpoint(req: AssistantRequest):
|
|
|
|
| 351 |
"""
|
| 352 |
Endpoint che gestisce l'intera pipeline:
|
| 353 |
1) Genera una query SPARQL dal messaggio dell'utente (prompt dedicato).
|
|
|
|
| 381 |
# Serializziamo l'ontologia in XML per fornirla al prompt (anche se si chiama 'turtle' va bene così).
|
| 382 |
ontology_turtle = ontology_graph.serialize(format="xml")
|
| 383 |
logger.debug("Ontologia serializzata con successo (XML).")
|
|
|
|
| 384 |
except Exception as e:
|
| 385 |
logger.warning(f"Impossibile serializzare l'ontologia in formato XML: {e}")
|
|
|
|
| 386 |
ontology_turtle = ""
|
| 387 |
|
| 388 |
# Creiamo il prompt di sistema per la generazione SPARQL
|
| 389 |
system_prompt_sparql = create_system_prompt_for_sparql(ontology_turtle)
|
|
|
|
| 390 |
# Chiamata al modello per generare la query SPARQL
|
| 391 |
try:
|
| 392 |
logger.debug("[assistant_endpoint] Chiamata HF per generare la query SPARQL...")
|
|
|
|
| 393 |
gen_sparql_output = hf_generation_client.chat.completions.create(
|
| 394 |
messages=[
|
| 395 |
{"role": "system", "content": system_prompt_sparql},
|
|
|
|
| 400 |
)
|
| 401 |
possible_query = gen_sparql_output["choices"][0]["message"]["content"].strip()
|
| 402 |
logger.info(f"[assistant_endpoint] Query generata dal modello: {possible_query}")
|
|
|
|
| 403 |
except Exception as ex:
|
| 404 |
logger.error(f"Errore nella generazione della query SPARQL: {ex}")
|
|
|
|
| 405 |
# Se fallisce la generazione, consideriamo la query come "NO_SPARQL"
|
| 406 |
possible_query = "NO_SPARQL"
|
| 407 |
|
|
|
|
| 412 |
else:
|
| 413 |
# Applichiamo la correzione avanzata
|
| 414 |
advanced_corrected = correct_sparql_syntax_advanced(possible_query)
|
|
|
|
| 415 |
# Verifichiamo la validità della query
|
| 416 |
if is_sparql_query_valid(advanced_corrected):
|
| 417 |
generated_query = advanced_corrected
|
| 418 |
logger.debug(f"[assistant_endpoint] Query SPARQL valida dopo correzione avanzata: {generated_query}")
|
|
|
|
| 419 |
else:
|
| 420 |
logger.debug("[assistant_endpoint] Query SPARQL non valida. Verrà ignorata.")
|
|
|
|
| 421 |
generated_query = None
|
| 422 |
|
| 423 |
# -----------------------------------------------------------------------
|
|
|
|
| 427 |
point = "" # variabile per contenere il punto (inizialmente nessuno)
|
| 428 |
if generated_query:
|
| 429 |
logger.debug(f"[assistant_endpoint] Esecuzione della query SPARQL:\n{generated_query}")
|
|
|
|
| 430 |
try:
|
| 431 |
query_result = ontology_graph.query(generated_query)
|
| 432 |
results = list(query_result)
|
| 433 |
logger.info(f"[assistant_endpoint] Query eseguita con successo. Numero risultati = {len(results)}")
|
|
|
|
| 434 |
except Exception as ex:
|
| 435 |
logger.error(f"[assistant_endpoint] Errore nell'esecuzione della query: {ex}")
|
|
|
|
| 436 |
results = []
|
|
|
|
|
|
|
| 437 |
# -----------------------------------------------------------------------
|
| 438 |
# STEP 3: Generazione della risposta finale stile "guida museale"
|
| 439 |
# -----------------------------------------------------------------------
|
| 440 |
system_prompt_guide = create_system_prompt_for_guide()
|
|
|
|
| 441 |
if generated_query and results:
|
| 442 |
# Caso: query generata + risultati SPARQL
|
| 443 |
# Convertiamo i risultati in una stringa più leggibile
|
|
|
|
| 463 |
"Rispondi in modo breve (max ~50 parole)."
|
| 464 |
)
|
| 465 |
logger.debug("[assistant_endpoint] Prompt di risposta con risultati SPARQL.")
|
|
|
|
| 466 |
elif generated_query and not results:
|
| 467 |
# Caso: query valida ma 0 risultati
|
| 468 |
second_prompt = (
|
|
|
|
| 472 |
"Nessun risultato dalla query. Prova comunque a rispondere con le tue conoscenze."
|
| 473 |
)
|
| 474 |
logger.debug("[assistant_endpoint] Prompt di risposta: query valida ma senza risultati.")
|
|
|
|
| 475 |
else:
|
| 476 |
# Caso: nessuna query generata
|
| 477 |
second_prompt = (
|
|
|
|
| 480 |
"Nessuna query SPARQL generata. Rispondi come puoi, riarrangiando le tue conoscenze."
|
| 481 |
)
|
| 482 |
logger.debug("[assistant_endpoint] Prompt di risposta: nessuna query generata.")
|
|
|
|
| 483 |
# Chiamata finale al modello per la risposta "guida museale"
|
| 484 |
try:
|
| 485 |
logger.debug("[assistant_endpoint] Chiamata HF per generare la risposta finale...")
|
|
|
|
| 486 |
final_output = hf_generation_client.chat.completions.create(
|
| 487 |
messages=[
|
| 488 |
{"role": "system", "content": second_prompt},
|
|
|
|
| 493 |
)
|
| 494 |
final_answer = final_output["choices"][0]["message"]["content"].strip()
|
| 495 |
logger.info(f"[assistant_endpoint] Risposta finale generata: {final_answer}")
|
|
|
|
| 496 |
except Exception as ex:
|
| 497 |
logger.error(f"Errore nella generazione della risposta finale: {ex}")
|
|
|
|
| 498 |
raise HTTPException(status_code=500, detail="Errore nella generazione della risposta in linguaggio naturale.")
|
| 499 |
|
| 500 |
# -----------------------------------------------------------------------
|
|
|
|
| 502 |
# -----------------------------------------------------------------------
|
| 503 |
final_ans = classify_and_translate(user_message, final_answer)
|
| 504 |
final_ans = final_ans.replace('\\"', "").replace('\"', "")
|
|
|
|
| 505 |
# -----------------------------------------------------------------------
|
| 506 |
# Restituzione in formato JSON
|
| 507 |
# -----------------------------------------------------------------------
|
|
|
|
| 509 |
return {
|
| 510 |
"query": generated_query,
|
| 511 |
"response": final_ans,
|
|
|
|
| 512 |
"point": point
|
| 513 |
}
|
| 514 |
# ---------------------------------------------------------------------------
|