tecuhtli commited on
Commit
a4a09ac
·
1 Parent(s): 9c8e3d6

Actualizo app.py, agrego nueva arquitectura Mori

Browse files
Files changed (1) hide show
  1. app.py +159 -57
app.py CHANGED
@@ -3,16 +3,13 @@
3
  #=====================================================================================
4
  # Importing Libraries ===============================================================
5
  #=====================================================================================
6
- import os, warnings, json, random, uuid, csv
7
- import numpy as np
8
  import streamlit as st
9
  import datetime as dt
10
  from pathlib import Path
11
- from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
12
- from Mori_TechnicalPrompts import answer_with_mori_rag, answer_with_mori_plain
13
  import torch
14
  from huggingface_hub import hf_hub_download, login
15
- from sentence_transformers import SentenceTransformer # RAG embeddings
16
  #***************************************************************************
17
  #Setting up variables
18
  #***************************************************************************
@@ -31,51 +28,86 @@ REPO_ID = "tecuhtli/Mori_FAISS_Full"
31
 
32
  def sidebar_params():
33
  with st.sidebar:
34
- st.title("🎮 Personalidad (FLAN-T5)")
35
 
36
  ss = st.session_state
37
 
 
38
  # Estado inicial
39
- ss.setdefault("show_llm_controls", False)
40
- ss.setdefault("persona", "Mori Exacto")
41
- ss.setdefault("mode", "beam") # 'beam' | 'sampling'
42
  ss.setdefault("max_new", 128)
43
  ss.setdefault("min_tok", 16)
44
  ss.setdefault("no_repeat", 3)
45
- ss.setdefault("num_beams", 4)
46
- ss.setdefault("length_penalty", 1.0)
47
- ss.setdefault("temperature", 0.7)
48
- ss.setdefault("top_p", 0.9)
49
  ss.setdefault("repetition_penalty", 1.0)
50
 
51
- # ----------------------------
52
- # Personalidad (presets)
53
- # ----------------------------
54
- st.header("💡 Personalidades predefinidas")
 
 
 
 
 
55
  c1, c2 = st.columns(2)
56
 
57
  with c1:
58
  if st.button("Exacto 🧐", use_container_width=True):
59
- ss.update({"persona": "exacto"})
60
  st.rerun()
61
 
62
  with c2:
63
  if st.button("Creativo 😃", use_container_width=True):
64
- ss.update({"persona": "creativo"})
65
  st.rerun()
66
 
67
  st.caption(f"Personalidad actual: **{ss.persona}**")
68
 
 
 
 
 
 
 
69
  st.markdown("---")
70
- st.title("👀 RAG")
71
- ss.setdefault("use_rag", True)
72
- ss.setdefault("rag_k", 1)
73
- ss.use_rag = st.checkbox(
74
- "Usar RAG (FAISS + One-Shot)",
75
- value=ss.use_rag,
76
- help="Recupera evidencias de la base FAISS de Mori en Hugging Face y las usa en el prompt."
 
 
 
 
 
 
77
  )
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  st.markdown("---")
80
  st.title("🧾 Vista previa del Prompt")
81
 
@@ -85,14 +117,14 @@ def sidebar_params():
85
  "Prompt actual:",
86
  ss["last_prompt"],
87
  height=200,
88
- disabled=True
89
  )
90
  else:
91
- st.caption("👉 Aún no se ha generado ningún prompt.")
92
 
93
- # ----------------------------
94
  # Construir diccionario de parámetros
95
- # ----------------------------
96
  params = {
97
  "persona": ss.persona,
98
  "mode": ss.mode,
@@ -100,14 +132,22 @@ def sidebar_params():
100
  "min_tokens": int(ss.min_tok),
101
  "no_repeat_ngram_size": int(ss.no_repeat),
102
  "repetition_penalty": float(ss.repetition_penalty),
 
 
103
  }
104
 
 
 
 
 
105
  return params
106
 
 
107
  #***************************************************************************
108
  # Functions
109
  #***************************************************************************
110
 
 
111
  # Function to clean the question field (por si luego lo quieres usar en un botón)
112
  def limpiar_input():
113
  st.session_state["entrada"] = ""
@@ -117,7 +157,7 @@ def get_model_path(folder_name):
117
  return Path("Models") / folder_name
118
 
119
  # Function to save user interaction
120
- def saving_interaction(question, response, user_id, use_of_rag, bot_personality):
121
  """
122
  Guarda la interacción en CSV y JSONL para análisis posterior.
123
  """
@@ -143,17 +183,55 @@ def saving_interaction(question, response, user_id, use_of_rag, bot_personality)
143
  "user_id": user_id,
144
  "pregunta": question,
145
  "respuesta": response,
 
146
  "uso_rag": use_of_rag,
147
  "personality": bot_personality
148
  }
149
  f_jsonl.write(json.dumps(registro, ensure_ascii=False) + "\n")
150
 
151
- # Function to load models within the huggingface repositories space
152
  @st.cache_resource
153
- def load_remote_model(repo_id: str, token: str = None):
154
- tokenizer = AutoTokenizer.from_pretrained(repo_id, token=token)
155
- model = AutoModelForSeq2SeqLM.from_pretrained(repo_id, token=token)
 
 
 
 
 
 
 
 
 
 
156
  return model, tokenizer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  #-------------------------------------------------------------------------
158
  # Seeds
159
  #-------------------------------------------------------------------------
@@ -199,12 +277,15 @@ if __name__ == "__main__":
199
  st.title("🤖 Mori - Tu Asistente Personal ⌨️")
200
 
201
  st.caption("🙋🏽‍ Puedes preguntarme conceptos sobre machine learning, estadística, visualización, BI, limpieza de datos y más.")
202
- st.caption("🙇🏽‍ Por el momento, solo puedo contestar preguntas simples como:")
203
 
204
  st.caption(" 🔹 **Definiciones** — Ejemplo: *¿Qué es machine learning?*")
205
  st.caption(" 🔹 **Procedimientos** — Ejemplo: *¿Cómo limpiar datos?*")
206
  st.caption(" 🔹 **Funcionalidad** — Ejemplo: *¿Para qué sirve un autoencoder?*")
207
 
 
 
 
208
  st.markdown("<br>", unsafe_allow_html=True)
209
 
210
  st.caption("🦾 Aún estoy aprendiendo. Puedes ver mi desarrollo aquí:")
@@ -218,7 +299,7 @@ if __name__ == "__main__":
218
  if ss.pop("_clear_entrada", False):
219
  if "entrada" in ss:
220
  del ss["entrada"]
221
-
222
  # 🧠 Flash de respuesta (la guardamos, pero la mostraremos después del form)
223
  _flash = ss.pop("_flash_response", None)
224
 
@@ -231,24 +312,45 @@ if __name__ == "__main__":
231
  if not user_question:
232
  st.info("Mori: ¿Podrías repetir eso? No entendí bien 😅")
233
  else:
234
- use_rag = st.session_state.get("use_rag", False)
235
-
236
  persona = GEN_PARAMS.get("persona", ss.persona)
237
 
238
- if use_rag:
239
- use_of_rag = 'Con RAG'
240
- response, prompt = answer_with_mori_rag(
241
- tokenizer, model, user_question,
242
- modo=persona,
243
- score_threshold= 0.84,
244
- verbose=False
 
 
 
 
 
245
  )
 
 
 
 
 
246
  else:
247
- use_of_rag = 'Sin RAG'
248
- response, prompt = answer_with_mori_plain(
249
- tokenizer, model, user_question,
250
- modo=persona
251
- )
 
 
 
 
 
 
 
 
 
 
 
 
252
 
253
  ss["last_prompt"] = prompt
254
  ss["just_generated"] = True
@@ -258,10 +360,10 @@ if __name__ == "__main__":
258
  ss.historial.append(("Tú", user_question, hora_actual))
259
 
260
  hora_actual = dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
261
- ss.historial.append(("Mori", response, hora_actual, use_of_rag, persona))
262
 
263
  # 💾 Guarda conversación
264
- saving_interaction(user_question, response, ss["user_id"], use_of_rag, persona)
265
 
266
  # 🟩 Guarda respuesta para mostrar después del rerun
267
  ss["_flash_response"] = response
@@ -285,12 +387,12 @@ if __name__ == "__main__":
285
  # 💾 Botón de descarga arriba del historial
286
  lineas = []
287
  for msg in reversed(ss.historial):
288
- if len(msg) == 5:
289
- autor, texto, hora, rag, bot_per = msg
290
- lineas.append(f"[{hora}] {autor}: {texto} RAG:{rag} Persoality:{bot_per}")
291
  else:
292
  autor, texto, hora = msg
293
- lineas.append(f"[{hora}] {autor}: {texto}")
294
  texto_chat = "\n\n".join(lineas)
295
 
296
  st.download_button(
 
3
  #=====================================================================================
4
  # Importing Libraries ===============================================================
5
  #=====================================================================================
 
 
6
  import streamlit as st
7
  import datetime as dt
8
  from pathlib import Path
9
+ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, AutoModelForCausalLM
10
+ from Mori_TechnicalPrompts import answer_with_mori_rag, answer_with_mori_plain, answer_with_qwen_base
11
  import torch
12
  from huggingface_hub import hf_hub_download, login
 
13
  #***************************************************************************
14
  #Setting up variables
15
  #***************************************************************************
 
28
 
29
  def sidebar_params():
30
  with st.sidebar:
31
+ st.title("🎮 Configuración de Mori")
32
 
33
  ss = st.session_state
34
 
35
+ # -------------------------
36
  # Estado inicial
37
+ # -------------------------
38
+ ss.setdefault("persona", "exacto") # "exacto" | "creativo"
39
+ ss.setdefault("mode", "beam")
40
  ss.setdefault("max_new", 128)
41
  ss.setdefault("min_tok", 16)
42
  ss.setdefault("no_repeat", 3)
 
 
 
 
43
  ss.setdefault("repetition_penalty", 1.0)
44
 
45
+ # NUEVO: backend
46
+ ss.setdefault("backend", "🍮 FLAN-T5 (fine-tuned)")
47
+ ss.setdefault("use_rag", True)
48
+
49
+ # -------------------------
50
+ # Personalidades
51
+ # -------------------------
52
+ st.header("🧠 Personalidades")
53
+
54
  c1, c2 = st.columns(2)
55
 
56
  with c1:
57
  if st.button("Exacto 🧐", use_container_width=True):
58
+ ss.persona = "exacto"
59
  st.rerun()
60
 
61
  with c2:
62
  if st.button("Creativo 😃", use_container_width=True):
63
+ ss.persona = "creativo"
64
  st.rerun()
65
 
66
  st.caption(f"Personalidad actual: **{ss.persona}**")
67
 
68
+ st.markdown(
69
+ """
70
+ 🔗 Cómo controlar la generación de texto:
71
+ - https://huggingface.co/blog/how-to-generate
72
+ """
73
+ )
74
  st.markdown("---")
75
+
76
+ # -------------------------
77
+ # Selección de modelo
78
+ # -------------------------
79
+ st.title("📙 Modelo")
80
+ ss.backend = st.radio(
81
+ "Elige el modelo de respuesta:",
82
+ options=[
83
+ "🍮 FLAN-T5 (fine-tuned)",
84
+ "👸 Qwen",
85
+ ],
86
+ index=0 if ss.backend == "🍮 FLAN-T5 (fine-tuned)" else 1,
87
+ help="Documentación:\n- FLAN-T5: https://huggingface.co/docs/transformers/model_doc/flan-t5\n- Qwen: https://huggingface.co/Qwen"
88
  )
89
 
90
+ # -------------------------
91
+ # RAG solo para FLAN-T5
92
+ # -------------------------
93
+
94
+ st.header("👀 RAG:")
95
+
96
+ if ss.backend == "🍮 FLAN-T5 (fine-tuned)":
97
+ ss.use_rag = st.checkbox(
98
+ "👷🏽 Usar RAG (FAISS + One-Shot)",
99
+ value=ss.use_rag,
100
+ help=(
101
+ "Documentación útil:\n"
102
+ "- RAG: https://huggingface.co/docs/transformers/en/model_doc/rag\n"
103
+ "- FAISS: https://faiss.ai/\n"
104
+ "- One-Shot Prompting: https://huggingface.co/docs/transformers/en/tasks/prompting"
105
+ ),
106
+ )
107
+ else:
108
+ ss.use_rag = False
109
+ st.caption("RAG no aplica en modo Qwen (usa solo el modelo base).")
110
+
111
  st.markdown("---")
112
  st.title("🧾 Vista previa del Prompt")
113
 
 
117
  "Prompt actual:",
118
  ss["last_prompt"],
119
  height=200,
120
+ disabled=True,
121
  )
122
  else:
123
+ st.caption("🔍 Aún no se ha generado ningún prompt.")
124
 
125
+ # -------------------------
126
  # Construir diccionario de parámetros
127
+ # -------------------------
128
  params = {
129
  "persona": ss.persona,
130
  "mode": ss.mode,
 
132
  "min_tokens": int(ss.min_tok),
133
  "no_repeat_ngram_size": int(ss.no_repeat),
134
  "repetition_penalty": float(ss.repetition_penalty),
135
+ "backend": ss.backend,
136
+ "use_rag": ss.use_rag,
137
  }
138
 
139
+ # Si ya tienes parámetros específicos para Qwen (como max_new_qwen),
140
+ # los puedes añadir aquí, por ejemplo:
141
+ # params["qwen_max_new"] = int(ss.qwen_max_new)
142
+
143
  return params
144
 
145
+
146
  #***************************************************************************
147
  # Functions
148
  #***************************************************************************
149
 
150
+ # Function to clean the question field (por si luego lo quieres usar en un botón)
151
  # Function to clean the question field (por si luego lo quieres usar en un botón)
152
  def limpiar_input():
153
  st.session_state["entrada"] = ""
 
157
  return Path("Models") / folder_name
158
 
159
  # Function to save user interaction
160
+ def saving_interaction(question, response, user_id, use_of_rag, bot_personality, modelo):
161
  """
162
  Guarda la interacción en CSV y JSONL para análisis posterior.
163
  """
 
183
  "user_id": user_id,
184
  "pregunta": question,
185
  "respuesta": response,
186
+ "modelo": modelo,
187
  "uso_rag": use_of_rag,
188
  "personality": bot_personality
189
  }
190
  f_jsonl.write(json.dumps(registro, ensure_ascii=False) + "\n")
191
 
 
192
  @st.cache_resource
193
+ def load_mori_model():
194
+ """
195
+ Carga Mori Técnico desde el Hub.
196
+ Cambia 'tecuhtli/mori-tecnico-model' por el ID real si es otro.
197
+ """
198
+ model_id = "tecuhtli/mori-tecnico-model"
199
+
200
+ token_kwargs = {}
201
+ if HF_TOKEN:
202
+ token_kwargs["token"] = HF_TOKEN # solo si el modelo es privado
203
+
204
+ tokenizer = AutoTokenizer.from_pretrained(model_id, **token_kwargs)
205
+ model = AutoModelForSeq2SeqLM.from_pretrained(model_id, **token_kwargs).to(device).eval()
206
  return model, tokenizer
207
+
208
+
209
+ # =============================================================================
210
+ # Carga de Qwen
211
+ # =============================================================================
212
+
213
+ QWEN_MODEL_NAME = "Qwen/Qwen2-1.5B-Instruct"
214
+
215
+
216
+ @st.cache_resource
217
+ def load_qwen_model():
218
+ """
219
+ Carga el modelo base de Qwen desde Hugging Face Hub (sin local_files_only).
220
+ Usa HF_TOKEN solo si el repo fuera privado.
221
+ """
222
+ token_kwargs = {}
223
+ if HF_TOKEN:
224
+ token_kwargs["token"] = HF_TOKEN # la mayoría de las veces no hace falta
225
+
226
+ tokenizer = AutoTokenizer.from_pretrained(QWEN_MODEL_NAME, **token_kwargs)
227
+ if tokenizer.pad_token is None:
228
+ tokenizer.pad_token = tokenizer.eos_token
229
+ tokenizer.padding_side = "right"
230
+
231
+ model = AutoModelForCausalLM.from_pretrained(QWEN_MODEL_NAME, **token_kwargs).to(device).eval()
232
+ return model, tokenizer
233
+
234
+
235
  #-------------------------------------------------------------------------
236
  # Seeds
237
  #-------------------------------------------------------------------------
 
277
  st.title("🤖 Mori - Tu Asistente Personal ⌨️")
278
 
279
  st.caption("🙋🏽‍ Puedes preguntarme conceptos sobre machine learning, estadística, visualización, BI, limpieza de datos y más.")
280
+ st.caption("🙇🏽‍ Por el momento FLAN-T5, solo puedo contestar preguntas simples como:")
281
 
282
  st.caption(" 🔹 **Definiciones** — Ejemplo: *¿Qué es machine learning?*")
283
  st.caption(" 🔹 **Procedimientos** — Ejemplo: *¿Cómo limpiar datos?*")
284
  st.caption(" 🔹 **Funcionalidad** — Ejemplo: *¿Para qué sirve un autoencoder?*")
285
 
286
+ st.caption("🔥 Qwen 1.5 corre con todas sus capacidades completas.")
287
+ st.caption(" 🔹 **Consejo** — Sé paciente y específico. Usar signos correctos ayuda a obtener mejores respuestas.")
288
+
289
  st.markdown("<br>", unsafe_allow_html=True)
290
 
291
  st.caption("🦾 Aún estoy aprendiendo. Puedes ver mi desarrollo aquí:")
 
299
  if ss.pop("_clear_entrada", False):
300
  if "entrada" in ss:
301
  del ss["entrada"]
302
+
303
  # 🧠 Flash de respuesta (la guardamos, pero la mostraremos después del form)
304
  _flash = ss.pop("_flash_response", None)
305
 
 
312
  if not user_question:
313
  st.info("Mori: ¿Podrías repetir eso? No entendí bien 😅")
314
  else:
315
+ backend = GEN_PARAMS.get("backend", "Mori (FT + RAG)")
 
316
  persona = GEN_PARAMS.get("persona", ss.persona)
317
 
318
+ # -----------------------------------------
319
+ # Backend Qwen base (sin RAG, sin FT)
320
+ # -----------------------------------------
321
+ if backend.startswith("👸 Qwen"):
322
+ modelito = 'Qwen'
323
+ qwen_model, qwen_tokenizer = load_qwen_model()
324
+ response, prompt = answer_with_qwen_base(
325
+ qwen_tokenizer,
326
+ qwen_model,
327
+ user_question,
328
+ persona,
329
+ max_new_tokens=GEN_PARAMS.get("qwen_max_new", 64),
330
  )
331
+ use_of_rag = "sin RAG"
332
+
333
+ # -----------------------------------------
334
+ # Backend Mori Técnico (FT + RAG / sin RAG)
335
+ # -----------------------------------------
336
  else:
337
+ modelito = 'FLAN-T5'
338
+ use_rag = st.session_state.get("use_rag", False)
339
+
340
+ if use_rag:
341
+ use_of_rag = 'Con RAG'
342
+ response, prompt = answer_with_mori_rag(
343
+ tokenizer, model, user_question,
344
+ modo=persona,
345
+ score_threshold=0.84,
346
+ verbose=False
347
+ )
348
+ else:
349
+ use_of_rag = 'Sin RAG'
350
+ response, prompt = answer_with_mori_plain(
351
+ tokenizer, model, user_question,
352
+ modo=persona
353
+ )
354
 
355
  ss["last_prompt"] = prompt
356
  ss["just_generated"] = True
 
360
  ss.historial.append(("Tú", user_question, hora_actual))
361
 
362
  hora_actual = dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
363
+ ss.historial.append(("Mori", response, hora_actual, modelito, use_of_rag, persona))
364
 
365
  # 💾 Guarda conversación
366
+ saving_interaction(user_question, response, ss["user_id"], modelito, use_of_rag, persona)
367
 
368
  # 🟩 Guarda respuesta para mostrar después del rerun
369
  ss["_flash_response"] = response
 
387
  # 💾 Botón de descarga arriba del historial
388
  lineas = []
389
  for msg in reversed(ss.historial):
390
+ if len(msg) == 6:
391
+ autor, texto, hora, model, rag, bot_per = msg
392
+ lineas.append(f"[{hora}], {autor}: {texto}, Model:{model}, RAG:{rag}, Persoality:{bot_per}")
393
  else:
394
  autor, texto, hora = msg
395
+ lineas.append(f"[{hora}], {autor}: {texto}")
396
  texto_chat = "\n\n".join(lineas)
397
 
398
  st.download_button(