AshenClock commited on
Commit
ac52c4d
·
verified ·
1 Parent(s): 4ce39fc

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +193 -0
app.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from rdflib import Graph
4
+ from pydantic import BaseModel
5
+ from fastapi import FastAPI, HTTPException
6
+ from huggingface_hub import InferenceClient
7
+ from typing import Optional
8
+
9
+ # Configurazione logging
10
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
11
+ logger = logging.getLogger(__name__)
12
+
13
+ # Configurazione API Hugging Face
14
+ API_KEY = os.getenv("HF_API_KEY")
15
+ if not API_KEY:
16
+ logger.error("HF_API_KEY non impostata nell'ambiente.")
17
+ raise EnvironmentError("HF_API_KEY non impostata nell'ambiente.")
18
+
19
+ client = InferenceClient(api_key=API_KEY)
20
+
21
+ # File RDF
22
+ RDF_FILE = "Ontologia.rdf"
23
+
24
+ # Caricamento RDF (riassunto)
25
+ def load_rdf_summary():
26
+ """
27
+ Carica un riassunto dell'ontologia dal file RDF.
28
+ Estrae le classi e le proprietà presenti nell'ontologia.
29
+ """
30
+ if not os.path.exists(RDF_FILE):
31
+ logger.error("Nessun file RDF trovato.")
32
+ return "Nessun file RDF trovato."
33
+ try:
34
+ g = Graph()
35
+ g.parse(RDF_FILE, format="xml")
36
+
37
+ # Estrazione semplificata di classi e proprietà
38
+ classes = set()
39
+ properties = set()
40
+ for s, p, o in g.triples((None, None, None)):
41
+ if "Class" in str(o):
42
+ classes.add(s)
43
+ if "Property" in str(o):
44
+ properties.add(s)
45
+
46
+ class_summary = "\n".join([f"- Classe: {cls}" for cls in classes])
47
+ prop_summary = "\n".join([f"- Proprietà: {prop}" for prop in properties])
48
+ return f"Classi:\n{class_summary}\n\nProprietà:\n{prop_summary}"
49
+ except Exception as e:
50
+ logger.error(f"Errore durante il parsing del file RDF: {e}")
51
+ return "Errore nel caricamento del file RDF."
52
+
53
+ rdf_context = load_rdf_summary()
54
+ logger.info("RDF Summary: %s", rdf_context)
55
+
56
+ # Validazione SPARQL
57
+ def validate_sparql_query(query: str, rdf_file_path: str) -> bool:
58
+ """
59
+ Verifica la validità della query SPARQL.
60
+ """
61
+ g = Graph()
62
+ try:
63
+ g.parse(rdf_file_path, format="xml")
64
+ g.query(query) # Solleva un'eccezione se la query non è valida
65
+ return True
66
+ except Exception as e:
67
+ logger.error(f"Errore durante la validazione della query SPARQL: {e}")
68
+ return False
69
+
70
+ # Prompt di Sistema
71
+ def create_system_message(rdf_context: str) -> str:
72
+ return f"""
73
+ Sei un assistente esperto nella generazione di query SPARQL basate su un'ontologia RDF, nell'interpretazione dei risultati delle query SPARQL in risposte naturali, e nel fare chatting minimale con i visitatori. In base alla domanda dell'utente, devi decidere se:
74
+
75
+ 1. Generare una query SPARQL per interrogare la base di conoscenza.
76
+ 2. Fornire una risposta naturale basata sui risultati di una query SPARQL.
77
+ 3. Rispondere con una risposta di chat minimale.
78
+
79
+ Ecco un riassunto dell'ontologia su cui devi lavorare:
80
+ {rdf_context}
81
+
82
+ Regole TASSATIVE:
83
+ 1. Se la domanda richiede una query SPARQL, restituisci la query SPARQL come testo semplice.
84
+ 2. Se la domanda richiede l'interpretazione di risultati SPARQL, restituisci una risposta naturale basata sui risultati.
85
+ 3. Se la domanda è una chat minimale, restituisci una risposta di chat.
86
+ 4. DEVI usare ESCLUSIVAMENTE questo prefisso di base (e NON modificarlo in nessun modo):
87
+ PREFIX base: <http://www.semanticweb.org/lucreziamosca/ontologies/2024/11/untitled-ontology-39/>
88
+ 5. NON generare alcun altro prefisso o URI inventato.
89
+ 6. Se non puoi rispondere con una query SPARQL valida, interpretare i risultati o fare chatting, scrivi:
90
+ "Non posso generare una query SPARQL, interpretare i risultati o fare una risposta di chat per questa richiesta."
91
+
92
+ Esempi:
93
+ - Domanda: "Quali sono le statue esposte del periodo medievale?"
94
+ Risposta:
95
+ PREFIX base: <http://www.semanticweb.org/lucreziamosca/ontologies/2024/11/untitled-ontology-39/> SELECT ?statua WHERE { ?statua a base:Statua . ?statua base:Periodo_Storico "Medioevo" . }
96
+
97
+ - Domanda: "La query ha restituito 5 statue. Puoi descriverle?"
98
+ Risposta:
99
+ Ecco le 5 statue medievali trovate: Statua1, Statua2, Statua3, Statua4, Statua5.
100
+
101
+ - Domanda: "Ciao!"
102
+ Risposta:
103
+ Ciao! Come posso aiutarti oggi?
104
+
105
+ RISPONDI ESCLUSIVAMENTE CON IL FORMATO SPECIFICATO.
106
+ """
107
+
108
+ # Funzione per chiamare il modello
109
+ async def call_model(messages, temperature=0.7, max_tokens=2048):
110
+ try:
111
+ response = client.chat.completions.create(
112
+ model="Qwen/Qwen2.5-72B-Instruct",
113
+ messages=messages,
114
+ temperature=temperature,
115
+ max_tokens=max_tokens,
116
+ top_p=0.7,
117
+ stream=False
118
+ )
119
+ raw_text = response["choices"][0]["message"]["content"]
120
+ # Rimuoviamo eventuali newline per forzare la singola riga
121
+ return raw_text.replace("\n", " ").strip()
122
+ except Exception as e:
123
+ logger.error(f"Errore nel modello: {e}")
124
+ raise HTTPException(status_code=500, detail=str(e))
125
+
126
+ # Funzione di Interpretazione dei Risultati SPARQL
127
+ def interpret_sparql_results(results):
128
+ """
129
+ Trasforma i risultati di una query SPARQL in una risposta naturale.
130
+ """
131
+ if not results:
132
+ return "Non sono state trovate informazioni corrispondenti alla tua richiesta."
133
+
134
+ # Esempio semplice: elenca gli elementi trovati
135
+ interpreted = "Ecco i risultati trovati: "
136
+ items = []
137
+ for row in results:
138
+ items.append(", ".join([f"{k}: {v}" for k, v in row.asdict().items()]))
139
+ interpreted += "; ".join(items) + "."
140
+
141
+ return interpreted
142
+
143
+ # FastAPI
144
+ app = FastAPI()
145
+
146
+ class QueryRequest(BaseModel):
147
+ message: str
148
+ max_tokens: int = 2048
149
+ temperature: float = 0.7
150
+
151
+ @app.post("/generate-response/")
152
+ async def generate_response(request: QueryRequest):
153
+ user_msg = request.message
154
+
155
+ # 1) Generazione della risposta (SPARQL, INTERPRET o CHAT)
156
+ system_msg = create_system_message(rdf_context)
157
+ messages = [
158
+ {"role": "system", "content": system_msg},
159
+ {"role": "user", "content": user_msg}
160
+ ]
161
+ response_text = await call_model(messages, request.temperature, request.max_tokens)
162
+ logger.info(f"Risposta generata dal modello: {response_text}")
163
+
164
+ # 2) Determinazione se la risposta è una query SPARQL
165
+ if response_text.startswith("PREFIX base:"):
166
+ sparql_query = response_text
167
+ # Validazione della query SPARQL
168
+ if validate_sparql_query(sparql_query, RDF_FILE):
169
+ # Esegui la query su GraphDB
170
+ try:
171
+ g = Graph()
172
+ g.parse(RDF_FILE, format="xml")
173
+ results = g.query(sparql_query)
174
+ # Interpreta i risultati in una risposta naturale
175
+ interpreted_response = interpret_sparql_results(results)
176
+ return {"type": "SPARQL", "response": interpreted_response}
177
+ except Exception as e:
178
+ logger.error(f"Errore durante l'esecuzione della query SPARQL: {e}")
179
+ return {"type": "SPARQL", "response": "Errore nell'esecuzione della query SPARQL."}
180
+ else:
181
+ return {"type": "SPARQL", "response": "Query SPARQL non valida."}
182
+
183
+ elif "Non posso generare una query SPARQL" in response_text:
184
+ # Risposta di errore dal modello
185
+ return {"type": "ERROR", "response": response_text}
186
+
187
+ else:
188
+ # Presumiamo che sia una risposta naturale o una chat
189
+ return {"type": "NATURAL", "response": response_text}
190
+
191
+ @app.get("/")
192
+ async def root():
193
+ return {"message": "Server attivo e pronto a generare risposte!"}