tecuhtli commited on
Commit
57290d8
·
verified ·
1 Parent(s): fc655fa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +208 -208
app.py CHANGED
@@ -1,208 +1,208 @@
1
- import os, sys
2
- os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0"
3
- import streamlit as st
4
- from pathlib import Path
5
- import torch, json, csv, warnings
6
- from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
7
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
8
- from pathlib import Path
9
- from unidecode import unidecode
10
- from datetime import datetime
11
- import uuid
12
-
13
- # 🆔 Asigna un ID de sesión si no existe
14
- if "user_id" not in st.session_state:
15
- st.session_state["user_id"] = str(uuid.uuid4())[:8] # Ej: "f6a9b3e2"
16
-
17
- def limpiar_input():
18
- st.session_state["entrada"] = ""
19
-
20
-
21
- def guardar_interaccion_dual(pregunta, respuesta, tipo, user_id):
22
- timestamp = datetime.now().isoformat()
23
-
24
- # 📁 Carpeta local (dentro del Space)
25
- stats_dir = Path("Statistics")
26
- stats_dir.mkdir(parents=True, exist_ok=True)
27
-
28
- # 📄 CSV
29
- archivo_csv = stats_dir / "conversaciones_log.csv"
30
- existe_csv = archivo_csv.exists()
31
-
32
- with open(archivo_csv, mode="a", encoding="utf-8", newline="") as f_csv:
33
- writer = csv.writer(f_csv)
34
- if not existe_csv:
35
- writer.writerow(["timestamp", "user_id", "tipo", "pregunta", "respuesta"])
36
- writer.writerow([timestamp, user_id, tipo, pregunta, respuesta])
37
-
38
- # 📄 JSONL
39
- archivo_jsonl = stats_dir / "conversaciones_log.jsonl"
40
- with open(archivo_jsonl, mode="a", encoding="utf-8") as f_jsonl:
41
- registro = {
42
- "timestamp": timestamp,
43
- "user_id": user_id,
44
- "tipo": tipo,
45
- "pregunta": pregunta,
46
- "respuesta": respuesta
47
- }
48
- f_jsonl.write(json.dumps(registro, ensure_ascii=False) + "\n")
49
-
50
-
51
- # Función para cargar modelos
52
- @st.cache_resource
53
- def load_model(path_str):
54
- path = Path(path_str).resolve()
55
- tokenizer = AutoTokenizer.from_pretrained(path, local_files_only=True)
56
- model = AutoModelForSeq2SeqLM.from_pretrained(path, local_files_only=True)
57
- return model, tokenizer
58
-
59
- def detectar_intencion(texto_usuario):
60
- texto = unidecode(texto_usuario.lower())
61
-
62
- social_keywords = [
63
- "hola", "chiste", "como estas", "gracias", "que pex", "broma", "saludos", "eres", "estudiante", "preguntar algo",
64
- "estas ahi", "que amable", "haces", "kiubo", "bro", "ey", "todo bien", "te puedo", "animo", "hasta luego", "me ayudas",
65
- "motiva", "no entiendo", "te gusta", "futbol", "quien eres", "sentimientos", "canelo", "america", "chivas", "background",
66
- "cuantos años", "proposito", "quien me habla", "te puedo preguntar", "ey bro", "quien te hizo", "que haces", "bonito",
67
- "piropo", "pex", "pasion", "hambre", "camara", "cansado", "adios"
68
- ]
69
-
70
- tecnico_keywords = [
71
- "modelo", "entrenamiento", "algoritmo", "regresion", "clasificacion", "overfitting", "datos", "que es",
72
- "define", "explicas", "pca", "cnn", "rnn", "clustering", "precision", "recall", "supervisado", "aprendizaje"
73
- ]
74
-
75
- if any(p in texto for p in social_keywords):
76
- return "Social"
77
- elif any(p in texto for p in tecnico_keywords):
78
- return "Técnica"
79
- else:
80
- return "Técnica"
81
-
82
-
83
- def responder_social(texto_usuario, social_model, social_tokenizer):
84
- device = next(social_model.parameters()).device
85
-
86
- inputs = social_tokenizer(
87
- texto_usuario, # ✅ sin agregar eos_token
88
- return_tensors="pt",
89
- padding=True,
90
- truncation=True,
91
- max_length=128 # ✅ especificado para evitar warning
92
- ).to(device)
93
-
94
- output_ids = social_model.generate(
95
- input_ids=inputs["input_ids"],
96
- attention_mask=inputs["attention_mask"], # ✅ FIX agregado
97
- max_length=50,
98
- pad_token_id=social_tokenizer.eos_token_id,
99
- do_sample=True,
100
- top_p=0.95,
101
- top_k=50
102
- )
103
-
104
- respuesta = social_tokenizer.decode(output_ids[0], skip_special_tokens=True)
105
- return respuesta.strip()
106
-
107
- def responder_tecnico(texto_usuario, technical_model, technical_tokenizer):
108
- entrada = "pregunta: " + texto_usuario
109
- device = next(technical_model.parameters()).device
110
-
111
- inputs = technical_tokenizer(
112
- entrada,
113
- return_tensors="pt",
114
- padding=True,
115
- truncation=True,
116
- max_length=128 # ✅ truncación explícita
117
- ).to(device)
118
-
119
- output = technical_model.generate(
120
- input_ids=inputs["input_ids"],
121
- attention_mask=inputs["attention_mask"], # ✅ FIX agregado
122
- max_length=64
123
- )
124
-
125
- respuesta = technical_tokenizer.decode(output[0], skip_special_tokens=True)
126
- return respuesta.strip()
127
-
128
-
129
- def responder_mori(texto_usuario):
130
- intencion = detectar_intencion(texto_usuario)
131
- #print("a ver: ", texto_usuario)
132
- if intencion == "Social":
133
- return responder_social(texto_usuario)
134
- elif intencion == "Técnica":
135
- return responder_tecnico(texto_usuario)
136
- else:
137
- return responder_tecnico(texto_usuario) #"🤔 No entendí bien... ¿quieres hablar de ciencia de datos o echar el chisme?"
138
-
139
-
140
-
141
- if "historial" not in st.session_state:
142
- st.session_state.historial = []
143
-
144
-
145
- # Modelo Técnico
146
- tokenizer_tecnico = AutoTokenizer.from_pretrained("tecuhtli/mori-tecnico-model")
147
- model_tecnico = AutoModelForSeq2SeqLM.from_pretrained("tecuhtli/mori-tecnico-model")
148
-
149
- # Modelo Social
150
- tokenizer_social = AutoTokenizer.from_pretrained("tecuhtli/mori-social-model")
151
- model_social = AutoModelForSeq2SeqLM.from_pretrained("tecuhtli/mori-social-model")
152
-
153
- # Dispositivo
154
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
155
- model_social = model_social.to(device)
156
- model_tecnico = model_tecnico.to(device)
157
-
158
- st.title("🤖 Mori - Tu Asistente Personal")
159
- st.header("Experto en Procesamiento de Datos 🐈‍")
160
-
161
- #entrada_usuario = st.text_area("📝 Escribe tu pregunta aquí")
162
-
163
- with st.form("formulario_mori"):
164
- entrada_usuario = st.text_area("📝 Escribe tu pregunta aquí", key="entrada", height=100)
165
- submitted = st.form_submit_button("Responder")
166
-
167
- if submitted:
168
- #if st.button("Responder") and entrada_usuario:
169
- opcion = detectar_intencion(entrada_usuario)
170
- if opcion == "Técnica":
171
- respuesta = "🧠 [Mori Técnico] " + responder_tecnico(entrada_usuario, modelo_tecnico, tokenizer_tecnico)
172
- st.success(respuesta)
173
- else:
174
- respuesta = "🤝 [Mori Social] " + responder_social(entrada_usuario, modelo_social, tokenizer_social)
175
- st.success(respuesta)
176
-
177
- # Guarda en historial
178
- st.session_state.historial.append(("Mori", respuesta))
179
- st.session_state.historial.append(("Tú", entrada_usuario))
180
-
181
- # 💾 Guarda en archivo para stats/dataset
182
- guardar_interaccion_dual(entrada_usuario, respuesta, opcion, st.session_state["user_id"])
183
-
184
-
185
-
186
-
187
-
188
- # 🔁 Muestra historial
189
- if st.session_state.historial:
190
- st.markdown("---")
191
- for autor, texto in reversed(st.session_state.historial):
192
- if autor == "Tú":
193
- st.markdown(f"🧍‍♂️ **{autor}**: {texto}")
194
- else:
195
- st.markdown(f"🤖 **{autor}**: {texto}")
196
-
197
-
198
- if st.session_state.historial:
199
- texto_chat = ""
200
- for autor, texto in st.session_state.historial:
201
- texto_chat += f"{autor}: {texto}\n\n"
202
-
203
- st.download_button(
204
- label="💾 Descargar conversación como .txt",
205
- data=texto_chat,
206
- file_name="conversacion_mori.txt",
207
- mime="text/plain"
208
- )
 
1
+ import os, sys
2
+ os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0"
3
+ import streamlit as st
4
+ from pathlib import Path
5
+ import torch, json, csv, warnings
6
+ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
7
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
8
+ from pathlib import Path
9
+ from unidecode import unidecode
10
+ from datetime import datetime
11
+ import uuid
12
+
13
+ # 🆔 Asigna un ID de sesión si no existe
14
+ if "user_id" not in st.session_state:
15
+ st.session_state["user_id"] = str(uuid.uuid4())[:8] # Ej: "f6a9b3e2"
16
+
17
+ def limpiar_input():
18
+ st.session_state["entrada"] = ""
19
+
20
+
21
+ def guardar_interaccion_dual(pregunta, respuesta, tipo, user_id):
22
+ timestamp = datetime.now().isoformat()
23
+
24
+ # 📁 Carpeta local (dentro del Space)
25
+ stats_dir = Path("Statistics")
26
+ stats_dir.mkdir(parents=True, exist_ok=True)
27
+
28
+ # 📄 CSV
29
+ archivo_csv = stats_dir / "conversaciones_log.csv"
30
+ existe_csv = archivo_csv.exists()
31
+
32
+ with open(archivo_csv, mode="a", encoding="utf-8", newline="") as f_csv:
33
+ writer = csv.writer(f_csv)
34
+ if not existe_csv:
35
+ writer.writerow(["timestamp", "user_id", "tipo", "pregunta", "respuesta"])
36
+ writer.writerow([timestamp, user_id, tipo, pregunta, respuesta])
37
+
38
+ # 📄 JSONL
39
+ archivo_jsonl = stats_dir / "conversaciones_log.jsonl"
40
+ with open(archivo_jsonl, mode="a", encoding="utf-8") as f_jsonl:
41
+ registro = {
42
+ "timestamp": timestamp,
43
+ "user_id": user_id,
44
+ "tipo": tipo,
45
+ "pregunta": pregunta,
46
+ "respuesta": respuesta
47
+ }
48
+ f_jsonl.write(json.dumps(registro, ensure_ascii=False) + "\n")
49
+
50
+
51
+ # Función para cargar modelos
52
+ @st.cache_resource
53
+ def load_model(path_str):
54
+ path = Path(path_str).resolve()
55
+ tokenizer = AutoTokenizer.from_pretrained(path, local_files_only=True)
56
+ model = AutoModelForSeq2SeqLM.from_pretrained(path, local_files_only=True)
57
+ return model, tokenizer
58
+
59
+ def detectar_intencion(texto_usuario):
60
+ texto = unidecode(texto_usuario.lower())
61
+
62
+ social_keywords = [
63
+ "hola", "chiste", "como estas", "gracias", "que pex", "broma", "saludos", "eres", "estudiante", "preguntar algo",
64
+ "estas ahi", "que amable", "haces", "kiubo", "bro", "ey", "todo bien", "te puedo", "animo", "hasta luego", "me ayudas",
65
+ "motiva", "no entiendo", "te gusta", "futbol", "quien eres", "sentimientos", "canelo", "america", "chivas", "background",
66
+ "cuantos años", "proposito", "quien me habla", "te puedo preguntar", "ey bro", "quien te hizo", "que haces", "bonito",
67
+ "piropo", "pex", "pasion", "hambre", "camara", "cansado", "adios"
68
+ ]
69
+
70
+ tecnico_keywords = [
71
+ "modelo", "entrenamiento", "algoritmo", "regresion", "clasificacion", "overfitting", "datos", "que es",
72
+ "define", "explicas", "pca", "cnn", "rnn", "clustering", "precision", "recall", "supervisado", "aprendizaje"
73
+ ]
74
+
75
+ if any(p in texto for p in social_keywords):
76
+ return "Social"
77
+ elif any(p in texto for p in tecnico_keywords):
78
+ return "Técnica"
79
+ else:
80
+ return "Técnica"
81
+
82
+
83
+ def responder_social(texto_usuario, social_model, social_tokenizer):
84
+ device = next(social_model.parameters()).device
85
+
86
+ inputs = social_tokenizer(
87
+ texto_usuario, # ✅ sin agregar eos_token
88
+ return_tensors="pt",
89
+ padding=True,
90
+ truncation=True,
91
+ max_length=128 # ✅ especificado para evitar warning
92
+ ).to(device)
93
+
94
+ output_ids = social_model.generate(
95
+ input_ids=inputs["input_ids"],
96
+ attention_mask=inputs["attention_mask"], # ✅ FIX agregado
97
+ max_length=50,
98
+ pad_token_id=social_tokenizer.eos_token_id,
99
+ do_sample=True,
100
+ top_p=0.95,
101
+ top_k=50
102
+ )
103
+
104
+ respuesta = social_tokenizer.decode(output_ids[0], skip_special_tokens=True)
105
+ return respuesta.strip()
106
+
107
+ def responder_tecnico(texto_usuario, technical_model, technical_tokenizer):
108
+ entrada = "pregunta: " + texto_usuario
109
+ device = next(technical_model.parameters()).device
110
+
111
+ inputs = technical_tokenizer(
112
+ entrada,
113
+ return_tensors="pt",
114
+ padding=True,
115
+ truncation=True,
116
+ max_length=128 # ✅ truncación explícita
117
+ ).to(device)
118
+
119
+ output = technical_model.generate(
120
+ input_ids=inputs["input_ids"],
121
+ attention_mask=inputs["attention_mask"], # ✅ FIX agregado
122
+ max_length=64
123
+ )
124
+
125
+ respuesta = technical_tokenizer.decode(output[0], skip_special_tokens=True)
126
+ return respuesta.strip()
127
+
128
+
129
+ def responder_mori(texto_usuario):
130
+ intencion = detectar_intencion(texto_usuario)
131
+ #print("a ver: ", texto_usuario)
132
+ if intencion == "Social":
133
+ return responder_social(texto_usuario)
134
+ elif intencion == "Técnica":
135
+ return responder_tecnico(texto_usuario)
136
+ else:
137
+ return responder_tecnico(texto_usuario) #"🤔 No entendí bien... ¿quieres hablar de ciencia de datos o echar el chisme?"
138
+
139
+
140
+
141
+ if "historial" not in st.session_state:
142
+ st.session_state.historial = []
143
+
144
+
145
+ # Modelo Técnico
146
+ tokenizer_tecnico = AutoTokenizer.from_pretrained("tecuhtli/mori-tecnico-model")
147
+ model_tecnico = AutoModelForSeq2SeqLM.from_pretrained("tecuhtli/mori-tecnico-model")
148
+
149
+ # Modelo Social
150
+ tokenizer_social = AutoTokenizer.from_pretrained("tecuhtli/mori-social-model")
151
+ model_social = AutoModelForSeq2SeqLM.from_pretrained("tecuhtli/mori-social-model")
152
+
153
+ # Dispositivo
154
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
155
+ model_social = model_social.to(device)
156
+ model_tecnico = model_tecnico.to(device)
157
+
158
+ st.title("🤖 Mori - Tu Asistente Personal")
159
+ st.header("Experto en Procesamiento de Datos 🐈‍")
160
+
161
+ #entrada_usuario = st.text_area("📝 Escribe tu pregunta aquí")
162
+
163
+ with st.form("formulario_mori"):
164
+ entrada_usuario = st.text_area("📝 Escribe tu pregunta aquí", key="entrada", height=100)
165
+ submitted = st.form_submit_button("Responder")
166
+
167
+ if submitted:
168
+ #if st.button("Responder") and entrada_usuario:
169
+ opcion = detectar_intencion(entrada_usuario)
170
+ if opcion == "Técnica":
171
+ respuesta = "🧠 [Mori Técnico] " + responder_tecnico(entrada_usuario, model_tecnico, tokenizer_tecnico)
172
+ st.success(respuesta)
173
+ else:
174
+ respuesta = "🤝 [Mori Social] " + responder_social(entrada_usuario, model_social, tokenizer_social)
175
+ st.success(respuesta)
176
+
177
+ # Guarda en historial
178
+ st.session_state.historial.append(("Mori", respuesta))
179
+ st.session_state.historial.append(("Tú", entrada_usuario))
180
+
181
+ # 💾 Guarda en archivo para stats/dataset
182
+ guardar_interaccion_dual(entrada_usuario, respuesta, opcion, st.session_state["user_id"])
183
+
184
+
185
+
186
+
187
+
188
+ # 🔁 Muestra historial
189
+ if st.session_state.historial:
190
+ st.markdown("---")
191
+ for autor, texto in reversed(st.session_state.historial):
192
+ if autor == "Tú":
193
+ st.markdown(f"🧍‍♂️ **{autor}**: {texto}")
194
+ else:
195
+ st.markdown(f"🤖 **{autor}**: {texto}")
196
+
197
+
198
+ if st.session_state.historial:
199
+ texto_chat = ""
200
+ for autor, texto in st.session_state.historial:
201
+ texto_chat += f"{autor}: {texto}\n\n"
202
+
203
+ st.download_button(
204
+ label="💾 Descargar conversación como .txt",
205
+ data=texto_chat,
206
+ file_name="conversacion_mori.txt",
207
+ mime="text/plain"
208
+ )