javiervz commited on
Commit
379044a
·
verified ·
1 Parent(s): 60e5b73

Update rag_hf.py

Browse files
Files changed (1) hide show
  1. rag_hf.py +54 -232
rag_hf.py CHANGED
@@ -8,7 +8,6 @@ import os
8
  import requests
9
  from rdflib import Graph as RDFGraph, Namespace
10
  from sentence_transformers import SentenceTransformer
11
- #from dotenv import load_dotenv
12
 
13
  # === STREAMLIT UI CONFIG ===
14
  st.set_page_config(
@@ -23,9 +22,7 @@ st.set_page_config(
23
  )
24
 
25
  # === CONFIGURATION ===
26
- #load_dotenv()
27
- ENDPOINT_URL = "https://api-inference.huggingface.co/models/NousResearch/Nous-Hermes-2-Mistral-7B-DPO"
28
- #ENDPOINT_URL = "https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.3"
29
  HF_API_TOKEN = os.getenv("HF_API_TOKEN")
30
  if not HF_API_TOKEN:
31
  st.error("⚠️ No se cargó el token HF_API_TOKEN desde los Secrets.")
@@ -38,61 +35,6 @@ EX = Namespace("http://example.org/lang/")
38
  # === CUSTOM CSS ===
39
  st.markdown("""
40
  <style>
41
- .header {
42
- color: #2c3e50;
43
- border-bottom: 2px solid #4f46e5;
44
- padding-bottom: 0.5rem;
45
- margin-bottom: 1.5rem;
46
- }
47
- .feature-card {
48
- background-color: #f8fafc;
49
- border-radius: 8px;
50
- padding: 1rem;
51
- margin: 0.5rem 0;
52
- border-left: 3px solid #4f46e5;
53
- }
54
- .response-card {
55
- background-color: #fdfdfd;
56
- color: #1f2937;
57
- border-radius: 8px;
58
- padding: 1.5rem;
59
- box-shadow: 0 2px 6px rgba(0,0,0,0.08);
60
- margin: 1rem 0;
61
- font-size: 1rem;
62
- line-height: 1.5;
63
- }
64
- .language-card {
65
- background-color: #f9fafb;
66
- border-radius: 8px;
67
- padding: 1rem;
68
- margin: 0.5rem 0;
69
- border: 1px solid #e5e7eb;
70
- }
71
- .sidebar-section {
72
- margin-bottom: 1.5rem;
73
- }
74
- .sidebar-title {
75
- font-weight: 600;
76
- color: #4f46e5;
77
- }
78
- .suggested-question {
79
- padding: 0.5rem;
80
- margin: 0.25rem 0;
81
- border-radius: 4px;
82
- cursor: pointer;
83
- transition: all 0.2s;
84
- }
85
- .suggested-question:hover {
86
- background-color: #f1f5f9;
87
- }
88
- .metric-badge {
89
- display: inline-block;
90
- background-color: #e8f4fc;
91
- padding: 0.25rem 0.5rem;
92
- border-radius: 4px;
93
- font-size: 0.85rem;
94
- margin-right: 0.5rem;
95
- }
96
  .tech-badge {
97
  background-color: #ecfdf5;
98
  color: #065f46;
@@ -109,7 +51,6 @@ st.markdown("""
109
  def load_all_components():
110
  embedder = SentenceTransformer(EMBEDDING_MODEL, device=DEVICE)
111
  methods = {}
112
- # Solo carga el método LinkGraph
113
  label, suffix, ttl, matrix_path = ("LinkGraph", "_hybrid_graphsage", "grafo_ttl_hibrido_graphsage.ttl", "embed_matrix_hybrid_graphsage.npy")
114
  with open(f"id_map{suffix}.pkl", "rb") as f:
115
  id_map = pickle.load(f)
@@ -149,6 +90,24 @@ def query_rdf(rdf, lang_id):
149
  except Exception as e:
150
  return [("error", str(e))]
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  def generate_response(matrix, id_map, G, rdf, user_question, k, embedder):
153
  ids = get_top_k(matrix, id_map, user_question, k, embedder)
154
  context = [get_context(G, i) for i in ids]
@@ -156,186 +115,49 @@ def generate_response(matrix, id_map, G, rdf, user_question, k, embedder):
156
  for i in ids:
157
  rdf_facts.extend([f"{p}: {v}" for p, v in query_rdf(rdf, i)])
158
 
159
- # Prompt para generar respuesta en español
160
- prompt_es = f"""<s>[INST] Eres un experto en lenguas indígenas sudamericanas. Utiliza estricta y únicamente la información a continuación para responder la pregunta del usuario en **español**.
161
- - No infieras ni asumas hechos que no estén explícitamente establecidos.
162
- - Si la respuesta es desconocida o insuficiente, di "No puedo responder con los datos disponibles."
163
- - Limita tu respuesta a 100 palabras.
164
- ### CONTEXTO: {chr(10).join(context)}
165
- ### RELACIONES RDF: {chr(10).join(rdf_facts)}
166
- ### PREGUNTA: {user_question}
167
- Respuesta: [/INST]"""
168
-
169
- # Prompt para generar respuesta en inglés
170
- prompt_en = f"""<s>[INST] You are an expert in South American indigenous languages. Use strictly and only the information below to answer the user question in **English**.
171
- - Do not infer or assume facts that are not explicitly stated.
172
- - If the answer is unknown or insufficient, say \"I cannot answer with the available data.\"
173
- - Limit your answer to 100 words.
174
- ### CONTEXT: {chr(10).join(context)}
175
- ### RDF RELATIONS: {chr(10).join(rdf_facts)}
176
- ### QUESTION: {user_question}
177
- Answer: [/INST]"""
178
-
179
- response_es = "Error al generar respuesta en español."
180
- response_en = "Error generating response in English."
181
-
182
- try:
183
- # Generar respuesta en español
184
- res_es = requests.post(
185
- ENDPOINT_URL,
186
- headers={"Authorization": f"Bearer {HF_API_TOKEN}", "Content-Type": "application/json"},
187
- json={"inputs": prompt_es}, timeout=60
188
- )
189
- out_es = res_es.json()
190
- if isinstance(out_es, list) and "generated_text" in out_es[0]:
191
- # Limpiar la respuesta para asegurar buen formato de markdown
192
- response_es = out_es[0]["generated_text"].replace(prompt_es.strip(), "").strip()
193
- response_es = response_es.replace('\n', ' ').replace(' ', ' ').strip() # Reemplazar saltos de línea con espacios, limpiar espacios dobles
194
 
195
- # Generar respuesta en inglés
196
- res_en = requests.post(
197
- ENDPOINT_URL,
198
- headers={"Authorization": f"Bearer {HF_API_TOKEN}", "Content-Type": "application/json"},
199
- json={"inputs": prompt_en}, timeout=60
200
- )
201
- out_en = res_en.json()
202
- if isinstance(out_en, list) and "generated_text" in out_en[0]:
203
- # Limpiar la respuesta para asegurar buen formato de markdown
204
- response_en = out_en[0]["generated_text"].replace(prompt_en.strip(), "").strip()
205
- response_en = response_en.replace('\n', ' ').replace(' ', ' ').strip() # Reemplazar saltos de línea con espacios, limpiar espacios dobles
206
 
207
- # Concatenar ambas respuestas con saltos de línea explícitos para el display
208
- full_response = (
209
- f"<b>Respuesta en español:</b><br>" # Usamos <br> para el salto de línea HTML
210
- f"{response_es}<br><br>" # Dos <br> para un doble salto de línea
211
- f"<b>Answer in English:</b><br>"
212
- f"{response_en}"
213
- )
214
- return full_response, ids, context, rdf_facts
215
- #except Exception as e:
216
- # return f"Ocurrió un error al generar la respuesta: {str(e)}", ids, context, rdf_facts
217
- except Exception as e:
218
- st.error(f"❌ Error técnico: {str(e)}")
219
- st.stop() # Detiene la ejecución para que veas el error
220
 
 
 
 
 
 
221
 
222
- # === MAIN APP ===
223
  def main():
224
  methods, embedder = load_all_components()
225
-
226
- st.markdown("""
227
- <div class="header">
228
- <h1>🌍 Atlas de Lenguas: Lenguas Indígenas Sudamericanas</h1>
229
- </div>
230
- """, unsafe_allow_html=True)
231
-
232
- with st.expander("📌 **Resumen General**", expanded=True):
233
- st.markdown("""
234
- Esta aplicación ofrece **análisis impulsado por IA, Grafos y RAGs (GraphRAGs)** de lenguas indígenas de América del Sur,
235
- integrando información de **Glottolog, Wikipedia y Wikidata**.
236
- """)
237
- #st.markdown("*Puedes preguntar en **español o inglés**, y el modelo responderá en **ambos idiomas**.*")
238
-
239
- with st.sidebar:
240
- st.markdown("### 📚 Información de Contacto")
241
- st.markdown("""
242
- - <span class="tech-badge">Correo: jxvera@gmail.com</span>
243
- """, unsafe_allow_html=True)
244
- st.markdown("---")
245
- st.markdown("### 🚀 Inicio Rápido")
246
- st.markdown("""
247
- 1. **Escribe una pregunta** en el cuadro de entrada
248
- 2. **Haz clic en 'Analizar'** para obtener la respuesta
249
- 3. **Explora los resultados** con los detalles expandibles
250
- """)
251
-
252
- st.markdown("---")
253
- st.markdown("### 🔍 Preguntas de Ejemplo")
254
- questions = [
255
- "¿Qué idiomas están en peligro en Brasil? (What languages are endangered in Brazil?)",
256
- "¿Qué idiomas se hablan en Perú? (What languages are spoken in Perú?)",
257
- "¿Cuáles idiomas están relacionados con el Quechua? (Which languages are related to Quechua?)",
258
- "¿Dónde se habla el Mapudungun? (Where is Mapudungun spoken?)"
259
- ]
260
-
261
- for q in questions:
262
- if st.button(q, key=f"suggested_{q}", use_container_width=True):
263
- st.session_state.query = q.split(" (")[0]
264
-
265
- st.markdown("---")
266
- st.markdown("### ⚙️ Detalles Técnicos")
267
- st.markdown("""
268
- - <span class="tech-badge">Embeddings</span> GraphSAGE
269
- - <span class="tech-badge">Modelo de Lenguaje</span> Mistral-7B-Instruct
270
- - <span class="tech-badge">Grafo de Conocimiento</span> Integración basada en RDF
271
- """, unsafe_allow_html=True)
272
-
273
- st.markdown("---")
274
- st.markdown("### 📂 Fuentes de Datos")
275
- st.markdown("""
276
- - **Glottolog** (Clasificación de idiomas)
277
- - **Wikipedia** (Resúmenes textuales)
278
- - **Wikidata** (Hechos estructurados)
279
- """)
280
-
281
- st.markdown("---")
282
- st.markdown("### 📊 Parámetros de Análisis")
283
- k = st.slider("Número de idiomas a analizar", 1, 10, 3)
284
- st.markdown("---")
285
- st.markdown("### 🔧 Opciones Avanzadas")
286
- show_ctx = st.checkbox("Mostrar información de contexto", False)
287
- show_rdf = st.checkbox("Mostrar hechos estructurados", False)
288
-
289
- st.markdown("### 📝 Haz una pregunta sobre lenguas indígenas")
290
- st.markdown("*(Puedes preguntar en español o inglés, y el modelo responderá en **ambos idiomas**.)*")
291
- query = st.text_input(
292
- "Ingresa tu pregunta:",
293
- value=st.session_state.get("query", ""),
294
- label_visibility="collapsed",
295
- placeholder="Ej. ¿Qué lenguas se hablan en Perú?"
296
- )
297
-
298
- if st.button("Analizar", type="primary", use_container_width=True):
299
- if not query:
300
- st.warning("Por favor, ingresa una pregunta")
301
- return
302
-
303
- label = "LinkGraph"
304
- method = methods[label]
305
-
306
- #st.markdown(f"#### Método {label}")
307
- #st.caption("Embeddings de GraphSAGE que capturan patrones en el grafo de conocimiento")
308
-
309
  start = datetime.datetime.now()
310
  response, lang_ids, context, rdf_data = generate_response(*method, query, k, embedder)
311
  duration = (datetime.datetime.now() - start).total_seconds()
312
-
313
- st.markdown(f"""
314
- <div class="response-card">
315
- {response}
316
- <div style="margin-top: 1rem;">
317
- <span class="metric-badge">⏱️ {duration:.2f}s</span>
318
- <span class="metric-badge">🌐 {len(lang_ids)} idiomas</span>
319
- </div>
320
- </div>
321
- """, unsafe_allow_html=True)
322
-
323
- if show_ctx:
324
- with st.expander(f"📖 Contexto de {len(lang_ids)} idiomas"):
325
- for lang_id, ctx in zip(lang_ids, context):
326
- st.markdown(f"<div class='language-card'>{ctx}</div>", unsafe_allow_html=True)
327
-
328
- if show_rdf:
329
- with st.expander("🔗 Hechos estructurados (RDF)"):
330
- st.code("\n".join(rdf_data))
331
-
332
- st.markdown("---")
333
- st.markdown("""
334
- <div style="font-size: 0.8rem; color: #64748b; text-align: center;">
335
- <b>📌 Nota:</b> Esta herramienta está diseñada para investigadores, lingüistas y preservacionistas culturales.
336
- Para mejores resultados, usa preguntas específicas sobre idiomas, familias o regiones.
337
- </div>
338
- """, unsafe_allow_html=True)
339
 
340
  if __name__ == "__main__":
341
- main()
 
8
  import requests
9
  from rdflib import Graph as RDFGraph, Namespace
10
  from sentence_transformers import SentenceTransformer
 
11
 
12
  # === STREAMLIT UI CONFIG ===
13
  st.set_page_config(
 
22
  )
23
 
24
  # === CONFIGURATION ===
25
+ ENDPOINT_URL = "https://api-inference.huggingface.co/models/HuggingFaceH4/zephyr-7b-beta"
 
 
26
  HF_API_TOKEN = os.getenv("HF_API_TOKEN")
27
  if not HF_API_TOKEN:
28
  st.error("⚠️ No se cargó el token HF_API_TOKEN desde los Secrets.")
 
35
  # === CUSTOM CSS ===
36
  st.markdown("""
37
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  .tech-badge {
39
  background-color: #ecfdf5;
40
  color: #065f46;
 
51
  def load_all_components():
52
  embedder = SentenceTransformer(EMBEDDING_MODEL, device=DEVICE)
53
  methods = {}
 
54
  label, suffix, ttl, matrix_path = ("LinkGraph", "_hybrid_graphsage", "grafo_ttl_hibrido_graphsage.ttl", "embed_matrix_hybrid_graphsage.npy")
55
  with open(f"id_map{suffix}.pkl", "rb") as f:
56
  id_map = pickle.load(f)
 
90
  except Exception as e:
91
  return [("error", str(e))]
92
 
93
+ def query_llm(prompt):
94
+ try:
95
+ res = requests.post(
96
+ ENDPOINT_URL,
97
+ headers={"Authorization": f"Bearer {HF_API_TOKEN}", "Content-Type": "application/json"},
98
+ json={"inputs": prompt}, timeout=60
99
+ )
100
+ res.raise_for_status()
101
+ out = res.json()
102
+ if isinstance(out, list):
103
+ if len(out) > 0 and isinstance(out[0], dict) and "generated_text" in out[0]:
104
+ return out[0]["generated_text"].strip()
105
+ elif isinstance(out, dict) and "generated_text" in out:
106
+ return out["generated_text"].strip()
107
+ return "Sin respuesta del modelo."
108
+ except Exception as e:
109
+ return f"Error al consultar el modelo: {str(e)}"
110
+
111
  def generate_response(matrix, id_map, G, rdf, user_question, k, embedder):
112
  ids = get_top_k(matrix, id_map, user_question, k, embedder)
113
  context = [get_context(G, i) for i in ids]
 
115
  for i in ids:
116
  rdf_facts.extend([f"{p}: {v}" for p, v in query_rdf(rdf, i)])
117
 
118
+ prompt_es = (
119
+ "Eres un experto en lenguas indígenas sudamericanas.\n"
120
+ "Usa solo la información del contexto y hechos RDF siguientes.\n\n"
121
+ + "### CONTEXTO:\n" + "\n".join(context) + "\n\n"
122
+ + "### RELACIONES RDF:\n" + "\n".join(rdf_facts) + "\n\n"
123
+ + f"### PREGUNTA:\n{user_question}\n\nRespuesta breve en español:"
124
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
+ prompt_en = (
127
+ "You are an expert in South American indigenous languages.\n"
128
+ "Use only the following context and RDF facts to answer.\n\n"
129
+ + "### CONTEXT:\n" + "\n".join(context) + "\n\n"
130
+ + "### RDF RELATIONS:\n" + "\n".join(rdf_facts) + "\n\n"
131
+ + f"### QUESTION:\n{user_question}\n\nShort answer in English:"
132
+ )
 
 
 
 
133
 
134
+ response_es = query_llm(prompt_es)
135
+ response_en = query_llm(prompt_en)
 
 
 
 
 
 
 
 
 
 
 
136
 
137
+ full_response = (
138
+ f"<b>Respuesta en español:</b><br>{response_es}<br><br>"
139
+ f"<b>Answer in English:</b><br>{response_en}"
140
+ )
141
+ return full_response, ids, context, rdf_facts
142
 
 
143
  def main():
144
  methods, embedder = load_all_components()
145
+ st.title("Atlas de Lenguas: Lenguas Indígenas Sudamericanas")
146
+ st.markdown("<span class='tech-badge'>Correo: jxvera@gmail.com</span>", unsafe_allow_html=True)
147
+ query = st.text_input("Escribe tu pregunta sobre lenguas indígenas:")
148
+ k = st.slider("Número de lenguas similares a recuperar", min_value=1, max_value=10, value=3)
149
+ if st.button("Analizar"):
150
+ method = methods["LinkGraph"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  start = datetime.datetime.now()
152
  response, lang_ids, context, rdf_data = generate_response(*method, query, k, embedder)
153
  duration = (datetime.datetime.now() - start).total_seconds()
154
+ st.markdown(response, unsafe_allow_html=True)
155
+ st.caption(f"⏱️ {duration:.2f} segundos | 🌐 {len(lang_ids)} idiomas analizados")
156
+ with st.expander("📖 Contexto"):
157
+ for ctx in context:
158
+ st.markdown(ctx)
159
+ with st.expander("🔗 Hechos RDF"):
160
+ st.code("\n".join(rdf_data))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
  if __name__ == "__main__":
163
+ main()