AshenClock commited on
Commit
d9ab7eb
·
verified ·
1 Parent(s): bfa70d6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -20
app.py CHANGED
@@ -6,6 +6,10 @@ from fastapi import FastAPI, HTTPException
6
  import rdflib
7
  from rdflib import RDF, RDFS, OWL
8
  from huggingface_hub import InferenceClient
 
 
 
 
9
 
10
  logging.basicConfig(
11
  level=logging.DEBUG,
@@ -27,6 +31,17 @@ HF_MODEL = "Qwen/Qwen2.5-72B-Instruct"
27
  MAX_CLASSES = 30
28
  MAX_PROPERTIES = 30
29
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  def extract_classes_and_properties(rdf_file:str) -> str:
32
  """
@@ -69,33 +84,28 @@ def extract_classes_and_properties(rdf_file:str) -> str:
69
  summary = f"""\
70
  # CLASSI (max {MAX_CLASSES})
71
  {txt_classes}
72
-
73
  # PROPRIETA' (max {MAX_PROPERTIES})
74
  {txt_props}
75
  """
76
  return summary
77
 
78
-
79
  knowledge_text = extract_classes_and_properties(RDF_FILE)
80
 
81
-
82
- def create_system_message(ont_text:str)->str:
83
  """
84
- Prompt di sistema robusto, con regole su query in una riga.
85
- Lasciamo un 'accenno' che, per parlare di 'materiale', potrebbe esserci
86
- una proprietà simile a 'base:materialeOpera' o analoga, ma NON tassativo.
87
  """
88
  return f"""
89
  Sei un assistente museale. Ecco un estratto di CLASSI e PROPRIETA' dell'ontologia (senza NamedIndividuals):
90
-
91
  --- ONTOLOGIA ---
92
  {ont_text}
93
  --- FINE ---
94
-
 
95
  Suggerimento: se l'utente chiede il 'materiale' di un'opera, potresti usare qualcosa come
96
  'base:materialeOpera' o un'altra proprietà simile (se esiste). Non è tassativo: usa
97
  la proprietà che ritieni più affine se ci sono riferimenti in ontologia.
98
-
99
  REGOLE STRINGENTI:
100
  1) Se l'utente chiede info su questa ontologia, genera SEMPRE una query SPARQL in UNA SOLA RIGA,
101
  con prefix:
@@ -104,21 +114,17 @@ REGOLE STRINGENTI:
104
  3) Se la domanda è generica (tipo 'Ciao, come stai?'), rispondi breve.
105
  4) Se trovi risultati, risposta finale = la query SPARQL (una sola riga).
106
  5) Se non trovi nulla, di' 'Nessuna info.'
107
- 6) Non multiline. Esempio: PREFIX base: <...> SELECT ?x WHERE {{ ... }}.
108
-
109
  FINE REGOLE
110
  """
111
 
112
-
113
  def create_explanation_prompt(results_str:str)->str:
114
  return f"""
115
  Ho ottenuto questi risultati SPARQL:
116
  {results_str}
117
-
118
  Ora fornisci una breve spiegazione museale (massimo ~10 righe), senza inventare oltre i risultati.
119
  """
120
 
121
-
122
  async def call_hf_model(messages, temperature=0.5, max_tokens=1024)->str:
123
  logger.debug("Chiamo HF con i seguenti messaggi:")
124
  for m in messages:
@@ -140,9 +146,6 @@ async def call_hf_model(messages, temperature=0.5, max_tokens=1024)->str:
140
  logger.error(f"HuggingFace error: {e}")
141
  raise HTTPException(status_code=500, detail=str(e))
142
 
143
-
144
- from fastapi import FastAPI
145
-
146
  app=FastAPI()
147
 
148
  class QueryRequest(BaseModel):
@@ -155,7 +158,11 @@ async def generate_response(req:QueryRequest):
155
  user_input=req.message
156
  logger.info(f"Utente dice: {user_input}")
157
 
158
- sys_msg=create_system_message(knowledge_text)
 
 
 
 
159
  msgs=[
160
  {"role":"system","content":sys_msg},
161
  {"role":"user","content":user_input}
@@ -182,7 +189,6 @@ async def generate_response(req:QueryRequest):
182
  sparql_query=r1
183
 
184
  # Esegui la query con rdflib
185
- import rdflib
186
  g=rdflib.Graph()
187
  try:
188
  g.parse(RDF_FILE,format="xml")
 
6
  import rdflib
7
  from rdflib import RDF, RDFS, OWL
8
  from huggingface_hub import InferenceClient
9
+ from sentence_transformers import SentenceTransformer
10
+ import faiss
11
+ import json
12
+ import numpy as np
13
 
14
  logging.basicConfig(
15
  level=logging.DEBUG,
 
31
  MAX_CLASSES = 30
32
  MAX_PROPERTIES = 30
33
 
34
+ # Carica i documenti e l'indice FAISS
35
+ with open("data/documents.json", "r", encoding="utf-8") as f:
36
+ documents = json.load(f)
37
+ index = faiss.read_index("data/faiss.index")
38
+ model = SentenceTransformer('all-MiniLM-L6-v2')
39
+
40
+ def retrieve_relevant_documents(query: str, top_k: int = 5):
41
+ query_embedding = model.encode([query], convert_to_numpy=True)
42
+ distances, indices = index.search(query_embedding, top_k)
43
+ relevant_docs = [documents[idx] for idx in indices[0]]
44
+ return relevant_docs
45
 
46
  def extract_classes_and_properties(rdf_file:str) -> str:
47
  """
 
84
  summary = f"""\
85
  # CLASSI (max {MAX_CLASSES})
86
  {txt_classes}
 
87
  # PROPRIETA' (max {MAX_PROPERTIES})
88
  {txt_props}
89
  """
90
  return summary
91
 
 
92
  knowledge_text = extract_classes_and_properties(RDF_FILE)
93
 
94
+ def create_system_message(ont_text:str, retrieved_docs:str)->str:
 
95
  """
96
+ Prompt di sistema robusto, con regole su query in una riga e
97
+ informazioni recuperate tramite RAG.
 
98
  """
99
  return f"""
100
  Sei un assistente museale. Ecco un estratto di CLASSI e PROPRIETA' dell'ontologia (senza NamedIndividuals):
 
101
  --- ONTOLOGIA ---
102
  {ont_text}
103
  --- FINE ---
104
+ Ecco alcune informazioni rilevanti recuperate dalla base di conoscenza:
105
+ {retrieved_docs}
106
  Suggerimento: se l'utente chiede il 'materiale' di un'opera, potresti usare qualcosa come
107
  'base:materialeOpera' o un'altra proprietà simile (se esiste). Non è tassativo: usa
108
  la proprietà che ritieni più affine se ci sono riferimenti in ontologia.
 
109
  REGOLE STRINGENTI:
110
  1) Se l'utente chiede info su questa ontologia, genera SEMPRE una query SPARQL in UNA SOLA RIGA,
111
  con prefix:
 
114
  3) Se la domanda è generica (tipo 'Ciao, come stai?'), rispondi breve.
115
  4) Se trovi risultati, risposta finale = la query SPARQL (una sola riga).
116
  5) Se non trovi nulla, di' 'Nessuna info.'
117
+ 6) Non multiline. Esempio: PREFIX base: <...> SELECT ?x WHERE { ... }.
 
118
  FINE REGOLE
119
  """
120
 
 
121
  def create_explanation_prompt(results_str:str)->str:
122
  return f"""
123
  Ho ottenuto questi risultati SPARQL:
124
  {results_str}
 
125
  Ora fornisci una breve spiegazione museale (massimo ~10 righe), senza inventare oltre i risultati.
126
  """
127
 
 
128
  async def call_hf_model(messages, temperature=0.5, max_tokens=1024)->str:
129
  logger.debug("Chiamo HF con i seguenti messaggi:")
130
  for m in messages:
 
146
  logger.error(f"HuggingFace error: {e}")
147
  raise HTTPException(status_code=500, detail=str(e))
148
 
 
 
 
149
  app=FastAPI()
150
 
151
  class QueryRequest(BaseModel):
 
158
  user_input=req.message
159
  logger.info(f"Utente dice: {user_input}")
160
 
161
+ # Recupera documenti rilevanti usando RAG
162
+ relevant_docs = retrieve_relevant_documents(user_input, top_k=3)
163
+ retrieved_text = "\n".join([doc['text'] for doc in relevant_docs])
164
+
165
+ sys_msg=create_system_message(knowledge_text, retrieved_text)
166
  msgs=[
167
  {"role":"system","content":sys_msg},
168
  {"role":"user","content":user_input}
 
189
  sparql_query=r1
190
 
191
  # Esegui la query con rdflib
 
192
  g=rdflib.Graph()
193
  try:
194
  g.parse(RDF_FILE,format="xml")