|
import os |
|
from fastapi import FastAPI, HTTPException |
|
from huggingface_hub import InferenceClient |
|
from rdflib import Graph |
|
from pydantic import BaseModel |
|
import logging |
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") |
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
API_KEY = os.getenv("HF_API_KEY") |
|
client = InferenceClient(api_key=API_KEY) |
|
|
|
|
|
RDF_FILE = "Ontologia.rdf" |
|
|
|
|
|
def load_rdf_summary(): |
|
if os.path.exists(RDF_FILE): |
|
try: |
|
g = Graph() |
|
g.parse(RDF_FILE, format="xml") |
|
|
|
classes = set() |
|
properties = set() |
|
|
|
for s, _, o in g.triples((None, None, None)): |
|
if "Class" in str(o) or "rdfs:Class" in str(o): |
|
classes.add(s) |
|
if "Property" in str(o): |
|
properties.add(s) |
|
|
|
classes_summary = "\n".join([f"- Classe: {cls}" for cls in classes]) |
|
properties_summary = "\n".join([f"- Proprietà: {prop}" for prop in properties]) |
|
return f"Classi:\n{classes_summary}\n\nProprietà:\n{properties_summary}" |
|
except Exception as e: |
|
logger.error(f"Errore durante il parsing del file RDF: {e}") |
|
return "Errore nel caricamento del file RDF." |
|
return "Nessun dato RDF trovato." |
|
|
|
rdf_context = load_rdf_summary() |
|
logger.info("RDF Summary: %s", rdf_context) |
|
|
|
|
|
def validate_sparql_query(query, rdf_file_path): |
|
try: |
|
g = Graph() |
|
g.parse(rdf_file_path, format="xml") |
|
g.query(query) |
|
return True |
|
except Exception as e: |
|
logger.error(f"Errore durante la validazione della query SPARQL: {e}") |
|
return False |
|
|
|
|
|
app = FastAPI() |
|
|
|
|
|
class QueryRequest(BaseModel): |
|
message: str |
|
max_tokens: int = 2048 |
|
temperature: float = 0.7 |
|
|
|
|
|
def create_system_message(rdf_context): |
|
return f""" |
|
Sei un assistente esperto nella generazione di query SPARQL basate su ontologie RDF. |
|
Ecco un riassunto dell'ontologia su cui devi lavorare: |
|
{rdf_context} |
|
|
|
Il tuo compito: |
|
- Genera esclusivamente query SPARQL valide in UNA SOLA RIGA. |
|
- Rispondi solo se la domanda è pertinente alle classi e proprietà fornite. |
|
- Se non puoi rispondere, di': "Non posso generare una query SPARQL per questa richiesta." |
|
""" |
|
|
|
async def generate_response(message, max_tokens, temperature): |
|
system_message = create_system_message(rdf_context) |
|
logger.debug("System Message: %s", system_message) |
|
logger.info("User Message: %s", message) |
|
|
|
messages = [ |
|
{"role": "system", "content": system_message}, |
|
{"role": "user", "content": message} |
|
] |
|
|
|
try: |
|
response = client.chat.completions.create( |
|
model="Qwen/Qwen2.5-72B-Instruct", |
|
messages=messages, |
|
temperature=temperature, |
|
max_tokens=max_tokens, |
|
top_p=0.7, |
|
stream=False, |
|
timeout=60 |
|
) |
|
logger.info("Raw Response: %s", response) |
|
return response['choices'][0]['message']['content'].replace("\n", " ").strip() |
|
except Exception as e: |
|
logger.error(f"Errore nell'elaborazione: {str(e)}") |
|
raise HTTPException(status_code=500, detail=f"Errore nell'elaborazione: {str(e)}") |
|
|
|
|
|
@app.post("/generate-query/") |
|
async def generate_query(request: QueryRequest): |
|
response = await generate_response(request.message, request.max_tokens, request.temperature) |
|
logger.info("Risposta generata dal modello: %s", response) |
|
|
|
if not (response.startswith("SELECT") or response.startswith("ASK")): |
|
return { |
|
"query": None, |
|
"explanation": "Non posso generare una query SPARQL per questa richiesta. Assicurati che la domanda sia coerente con i dati RDF forniti." |
|
} |
|
|
|
if not validate_sparql_query(response, RDF_FILE): |
|
return { |
|
"query": None, |
|
"explanation": "La query generata non è valida rispetto alla base di conoscenza RDF. Assicurati di chiedere informazioni che siano presenti nell'ontologia." |
|
} |
|
|
|
return {"query": response, "explanation": "Ecco la query generata correttamente in una riga pronta per GraphDB."} |
|
|
|
|
|
@app.get("/") |
|
async def root(): |
|
return {"message": "Il server è attivo e pronto a generare query SPARQL!"} |