jeysshon commited on
Commit
54d10b3
·
verified ·
1 Parent(s): f808679

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -127
app.py CHANGED
@@ -9,85 +9,44 @@ from urllib.parse import quote
9
  os.environ["GRPC_ENABLE_FORK_SUPPORT"] = "False"
10
  os.environ["ABSL_LOG_LEVEL"] = "ERROR"
11
 
12
- # Rutas de archivos (asumiendo que están en la carpeta raíz del repo)
13
- EXCEL_PATH = "MasterData SISO - Actualizada - Jan-29-2025.xlsx"
14
- AUDIO_PATH = "Manual del Operador de Tienda.wav"
15
- CERTIFICATE_TEMPLATE = "certificate_template_.pdf"
16
-
17
- # Convertimos la ruta del audio a un path tipo URL (opcional, útil localmente)
18
- abs_path = os.path.abspath(AUDIO_PATH).replace("\\", "/")
19
- AUDIO_URL = f"file:///{quote(abs_path)}"
20
 
21
  # ===== PREGUNTAS DEL EXAMEN =====
22
  PREGUNTAS = [
23
- {
24
- "pregunta": "1. ¿Qué debe hacer el Operador cuando se active la alerta de la pantalla naranja? 🚨",
25
- "opciones": [
26
- "A) Ignorar la alerta ❌🚨",
27
- "B) Informar al Jefe de Tienda 👨💼",
28
- "C) Recontar el dinero 💰",
29
- "D) Cerrar el turno 🔒"
30
- ],
31
- "respuesta": "B"
32
- },
33
- {
34
- "pregunta": "2. ¿Quién verifica la cantidad de dinero? 💼💵",
35
- "opciones": [
36
- "A) El encargado de turno 👷♂️",
37
- "B) El Jefe de Tienda ❌",
38
- "C) El Supervisor 👮♂️",
39
- "D) El Operador nuevamente 🔄"
40
- ],
41
- "respuesta": "A"
42
- },
43
- {
44
- "pregunta": "3. ¿Hasta cuándo es responsable el Operador del efectivo? ",
45
- "opciones": [
46
- "A) Hasta finalizar su jornada 🕔",
47
- "B) Hasta la última recogida 📦",
48
- "C) Hasta cerrar el turno 🔐",
49
- "D) Hasta entregar al Jefe 👨💼"
50
- ],
51
- "respuesta": "B"
52
- },
53
- {
54
- "pregunta": "4. ¿Qué hace el Jefe tras recoger el dinero? 💼➡️📦",
55
- "opciones": [
56
- "A) Depositar en caja 🏦",
57
- "B) Contar nuevamente 🔢",
58
- "C) Actualizar ISSWEB 💻✅",
59
- "D) Entregar al Supervisor 👮♂️"
60
- ],
61
- "respuesta": "C"
62
- },
63
- {
64
- "pregunta": "5. ¿Qué hacer con cada sobre antes de guardarlo? 📦👀",
65
- "opciones": [
66
- "A) Mostrar 5s al CCTV ⏱️✅",
67
- "B) Contar otra vez 🔢",
68
- "C) Entregar al Jefe 👨💼",
69
- "D) Guardar en bolsillo 👖"
70
- ],
71
- "respuesta": "A"
72
- }
73
  ]
74
 
75
  # ===== FUNCIONES PARA MANEJO DEL EXCEL =====
76
  def cargar_datos():
 
77
  try:
78
- df = pd.read_excel(
79
- EXCEL_PATH,
80
- usecols=[
81
- 'SAPId',
82
- 'Número de personal',
83
- 'Status ocupación',
84
- 'Genero',
85
- 'Centro de coste',
86
- 'FuncionName'
87
- ],
88
- dtype={'SAPId': 'int32'}
89
- )
90
- # Si faltan columnas, las agregamos
91
  for col in ['Fecha', 'Calificacion', 'Curso']:
92
  if col not in df.columns:
93
  df[col] = None
@@ -97,7 +56,7 @@ def cargar_datos():
97
  return {}
98
 
99
  def actualizar_excel(sap_id, aprobado):
100
- """Marca en Excel la fecha, el resultado y el curso para el SAP ID dado."""
101
  try:
102
  df = pd.read_excel(EXCEL_PATH)
103
  mask = df['SAPId'] == sap_id
@@ -111,26 +70,28 @@ def actualizar_excel(sap_id, aprobado):
111
  # ===== CHAINLIT =====
112
  @cl.on_chat_start
113
  async def inicio():
 
114
  SAP_DICT = cargar_datos()
115
  cl.user_session.set("SAP_DICT", SAP_DICT)
116
  await cl.Message("🚀 **Sistema de Certificación - Operador de Tienda**\nIngrese su SAP ID:").send()
117
 
118
  @cl.on_message
119
  async def manejar_mensaje(message: cl.Message):
 
120
  SAP_DICT = cl.user_session.get("SAP_DICT")
121
  user_data = cl.user_session.get("user_data")
122
-
123
- # Si el usuario ya está en examen, verificamos la respuesta
124
  if user_data and user_data.get("en_examen"):
125
  await procesar_respuesta(message)
126
  return
127
-
128
- # Sino, interpretamos como SAP ID
129
  try:
130
  sap_id = int(message.content)
131
  if sap_id not in SAP_DICT:
132
  return await cl.Message("⛔️ ID no registrado").send()
133
-
134
  usuario = SAP_DICT[sap_id]
135
  respuesta = f"""
136
  🔍 **Usuario identificado** 🔍
@@ -139,104 +100,77 @@ async def manejar_mensaje(message: cl.Message):
139
  ├ Función: {usuario['FuncionName']}
140
  └ Centro Coste: {usuario['Centro de coste']}
141
  """
142
-
143
- # Guardamos datos en la sesión
144
  cl.user_session.set("user_data", {
145
  "sap_id": sap_id,
146
  "puntaje": 0,
147
  "pregunta_actual": 0,
148
  "en_examen": True
149
  })
150
-
151
  await cl.Message(content=respuesta).send()
152
  await mostrar_pregunta()
153
-
154
  except ValueError:
155
  await cl.Message("⚠️ Solo números permitidos (Ej: 60000001)").send()
156
 
157
  async def mostrar_pregunta():
 
158
  user_data = cl.user_session.get("user_data")
159
  num_pregunta = user_data["pregunta_actual"]
160
-
161
- # Si ya no hay más preguntas, mostramos resultado final
162
  if num_pregunta >= len(PREGUNTAS):
163
  await mostrar_resultado()
164
  return
165
-
166
  p = PREGUNTAS[num_pregunta]
167
  mensaje = f"📝 **Pregunta {num_pregunta + 1}**\n{p['pregunta']}\n\n" + "\n".join(p['opciones'])
168
  await cl.Message(content=mensaje + "\n\n🔘 Respuesta (A/B/C/D):").send()
169
 
170
  async def procesar_respuesta(message: cl.Message):
 
171
  user_data = cl.user_session.get("user_data")
172
  num_pregunta = user_data["pregunta_actual"]
173
-
174
  respuesta = message.content.strip().upper()
175
-
176
- # Validar la respuesta
177
- if len(respuesta) != 1 or respuesta not in ['A', 'B', 'C', 'D']:
178
- await cl.Message(content="⚠️ **Formato incorrecto**. Respuesta = A/B/C/D").send()
179
  return
180
-
181
  correcta = PREGUNTAS[num_pregunta]['respuesta']
182
  if respuesta == correcta:
183
  user_data["puntaje"] += 1
184
  await cl.Message("✅ ¡Respuesta correcta! +1 punto").send()
185
  else:
186
  await cl.Message(f"❌ Respuesta incorrecta. La correcta es: {correcta}").send()
187
-
188
  user_data["pregunta_actual"] += 1
189
  cl.user_session.set("user_data", user_data)
190
-
191
- # Si quedan preguntas, mostramos la siguiente
192
  if user_data["pregunta_actual"] < len(PREGUNTAS):
193
  await mostrar_pregunta()
194
  else:
195
  await mostrar_resultado()
196
 
197
  async def mostrar_resultado():
 
198
  user_data = cl.user_session.get("user_data")
199
- SAP_DICT = cl.user_session.get("SAP_DICT")
200
-
201
- # Nota de aprobación (3/5)
202
  aprobado = user_data['puntaje'] >= 3
203
  actualizar_excel(user_data['sap_id'], aprobado)
204
-
205
- mensaje = (
206
- "🎉 **¡FELICITACIONES! APROBADO**\n"
207
- if aprobado else
208
- "❌ **LO SENTIMOS, REPROBADO**\n"
209
- )
210
  mensaje += f"Puntaje Final: {user_data['puntaje']}/5"
211
-
212
- if aprobado:
213
- # Solo mostramos la plantilla PDF tal cual
214
- await cl.Message(
215
- content=mensaje,
216
- elements=[
217
- # Se envía la plantilla como archivo descargable
218
- cl.File(path=CERTIFICATE_TEMPLATE, name="Certificado de Aprobación")
219
- ]
220
- ).send()
221
  else:
222
- # Si no aprueba, muestra el audio
223
- await cl.Message(
224
- content=mensaje,
225
- elements=[
226
- cl.Audio(
227
- name="🎧 Material de Refuerzo",
228
- path=AUDIO_PATH,
229
- display="inline",
230
- autoplay=False
231
- )
232
- ]
233
- ).send()
234
-
235
- # Reiniciamos para un nuevo examen
236
  cl.user_session.set("user_data", None)
237
  await cl.Message(content="\nIngrese nuevo SAP ID para otro examen:").send()
238
 
239
- # ===== EJECUCIÓN LOCAL (Chainlit) =====
240
  if __name__ == "__main__":
241
  from chainlit.cli import run_chainlit
242
  run_chainlit(__file__)
 
9
  os.environ["GRPC_ENABLE_FORK_SUPPORT"] = "False"
10
  os.environ["ABSL_LOG_LEVEL"] = "ERROR"
11
 
12
+ # Definir rutas absolutas para asegurar que los archivos sean accesibles
13
+ EXCEL_PATH = os.path.abspath("MasterData SISO - Actualizada - Jan-29-2025.xlsx")
14
+ AUDIO_PATH = os.path.abspath("Manual del Operador de Tienda.wav")
15
+ CERTIFICATE_TEMPLATE = os.path.abspath("certificate_template_.pdf")
 
 
 
 
16
 
17
  # ===== PREGUNTAS DEL EXAMEN =====
18
  PREGUNTAS = [
19
+ {"pregunta": "1. ¿Qué debe hacer el Operador cuando se active la alerta de la pantalla naranja? 🚨",
20
+ "opciones": ["A) Ignorar la alerta ❌🚨", "B) Informar al Jefe de Tienda 👨💼",
21
+ "C) Recontar el dinero 💰", "D) Cerrar el turno 🔒"],
22
+ "respuesta": "B"},
23
+
24
+ {"pregunta": "2. ¿Quién verifica la cantidad de dinero? 💼💵",
25
+ "opciones": ["A) El encargado de turno 👷♂️", "B) El Jefe de Tienda ❌",
26
+ "C) El Supervisor 👮♂️", "D) El Operador nuevamente 🔄"],
27
+ "respuesta": "A"},
28
+
29
+ {"pregunta": "3. ¿Hasta cuándo es responsable el Operador del efectivo? ⏳",
30
+ "opciones": ["A) Hasta finalizar su jornada 🕔", "B) Hasta la última recogida 📦",
31
+ "C) Hasta cerrar el turno 🔐", "D) Hasta entregar al Jefe 👨💼"],
32
+ "respuesta": "B"},
33
+
34
+ {"pregunta": "4. ¿Qué hace el Jefe tras recoger el dinero? 💼➡️📦",
35
+ "opciones": ["A) Depositar en caja 🏦", "B) Contar nuevamente 🔢",
36
+ "C) Actualizar ISSWEB 💻✅", "D) Entregar al Supervisor 👮♂️"],
37
+ "respuesta": "C"},
38
+
39
+ {"pregunta": "5. ¿Qué hacer con cada sobre antes de guardarlo? 📦👀",
40
+ "opciones": ["A) Mostrar 5s al CCTV ⏱️✅", "B) Contar otra vez 🔢",
41
+ "C) Entregar al Jefe 👨💼", "D) Guardar en bolsillo 👖"],
42
+ "respuesta": "A"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  ]
44
 
45
  # ===== FUNCIONES PARA MANEJO DEL EXCEL =====
46
  def cargar_datos():
47
+ """Carga los datos de Excel y los devuelve en un diccionario."""
48
  try:
49
+ df = pd.read_excel(EXCEL_PATH, dtype={'SAPId': 'int32'})
 
 
 
 
 
 
 
 
 
 
 
 
50
  for col in ['Fecha', 'Calificacion', 'Curso']:
51
  if col not in df.columns:
52
  df[col] = None
 
56
  return {}
57
 
58
  def actualizar_excel(sap_id, aprobado):
59
+ """Actualiza la hoja de Excel con el estado del usuario."""
60
  try:
61
  df = pd.read_excel(EXCEL_PATH)
62
  mask = df['SAPId'] == sap_id
 
70
  # ===== CHAINLIT =====
71
  @cl.on_chat_start
72
  async def inicio():
73
+ """Inicia el chat y solicita el SAP ID."""
74
  SAP_DICT = cargar_datos()
75
  cl.user_session.set("SAP_DICT", SAP_DICT)
76
  await cl.Message("🚀 **Sistema de Certificación - Operador de Tienda**\nIngrese su SAP ID:").send()
77
 
78
  @cl.on_message
79
  async def manejar_mensaje(message: cl.Message):
80
+ """Maneja la entrada del usuario."""
81
  SAP_DICT = cl.user_session.get("SAP_DICT")
82
  user_data = cl.user_session.get("user_data")
83
+
84
+ # Si ya está en examen, procesa la respuesta
85
  if user_data and user_data.get("en_examen"):
86
  await procesar_respuesta(message)
87
  return
88
+
89
+ # Procesamos como SAP ID
90
  try:
91
  sap_id = int(message.content)
92
  if sap_id not in SAP_DICT:
93
  return await cl.Message("⛔️ ID no registrado").send()
94
+
95
  usuario = SAP_DICT[sap_id]
96
  respuesta = f"""
97
  🔍 **Usuario identificado** 🔍
 
100
  ├ Función: {usuario['FuncionName']}
101
  └ Centro Coste: {usuario['Centro de coste']}
102
  """
103
+
 
104
  cl.user_session.set("user_data", {
105
  "sap_id": sap_id,
106
  "puntaje": 0,
107
  "pregunta_actual": 0,
108
  "en_examen": True
109
  })
110
+
111
  await cl.Message(content=respuesta).send()
112
  await mostrar_pregunta()
113
+
114
  except ValueError:
115
  await cl.Message("⚠️ Solo números permitidos (Ej: 60000001)").send()
116
 
117
  async def mostrar_pregunta():
118
+ """Muestra la siguiente pregunta del examen."""
119
  user_data = cl.user_session.get("user_data")
120
  num_pregunta = user_data["pregunta_actual"]
121
+
 
122
  if num_pregunta >= len(PREGUNTAS):
123
  await mostrar_resultado()
124
  return
125
+
126
  p = PREGUNTAS[num_pregunta]
127
  mensaje = f"📝 **Pregunta {num_pregunta + 1}**\n{p['pregunta']}\n\n" + "\n".join(p['opciones'])
128
  await cl.Message(content=mensaje + "\n\n🔘 Respuesta (A/B/C/D):").send()
129
 
130
  async def procesar_respuesta(message: cl.Message):
131
+ """Procesa la respuesta de la pregunta actual."""
132
  user_data = cl.user_session.get("user_data")
133
  num_pregunta = user_data["pregunta_actual"]
134
+
135
  respuesta = message.content.strip().upper()
136
+ if respuesta not in ['A', 'B', 'C', 'D']:
137
+ await cl.Message("⚠️ **Formato incorrecto**. Respuesta = A/B/C/D").send()
 
 
138
  return
139
+
140
  correcta = PREGUNTAS[num_pregunta]['respuesta']
141
  if respuesta == correcta:
142
  user_data["puntaje"] += 1
143
  await cl.Message("✅ ¡Respuesta correcta! +1 punto").send()
144
  else:
145
  await cl.Message(f"❌ Respuesta incorrecta. La correcta es: {correcta}").send()
146
+
147
  user_data["pregunta_actual"] += 1
148
  cl.user_session.set("user_data", user_data)
149
+
 
150
  if user_data["pregunta_actual"] < len(PREGUNTAS):
151
  await mostrar_pregunta()
152
  else:
153
  await mostrar_resultado()
154
 
155
  async def mostrar_resultado():
156
+ """Muestra el resultado final del examen y adjunta el PDF o el audio."""
157
  user_data = cl.user_session.get("user_data")
 
 
 
158
  aprobado = user_data['puntaje'] >= 3
159
  actualizar_excel(user_data['sap_id'], aprobado)
160
+
161
+ mensaje = f"🎉 **¡FELICITACIONES! APROBADO**\n" if aprobado else f"❌ **LO SENTIMOS, REPROBADO**\n"
 
 
 
 
162
  mensaje += f"Puntaje Final: {user_data['puntaje']}/5"
163
+
164
+ if aprobado and os.path.exists(CERTIFICATE_TEMPLATE):
165
+ await cl.Message(content=mensaje, elements=[cl.File(path=CERTIFICATE_TEMPLATE, name="Certificado de Aprobación")]).send()
166
+ elif not aprobado and os.path.exists(AUDIO_PATH):
167
+ await cl.Message(content=mensaje, elements=[cl.Audio(name="🎧 Material de Refuerzo", path=AUDIO_PATH, display="inline", autoplay=False)]).send()
 
 
 
 
 
168
  else:
169
+ await cl.Message(content=mensaje + "\n⚠️ **Error: No se encontró el archivo**").send()
170
+
 
 
 
 
 
 
 
 
 
 
 
 
171
  cl.user_session.set("user_data", None)
172
  await cl.Message(content="\nIngrese nuevo SAP ID para otro examen:").send()
173
 
 
174
  if __name__ == "__main__":
175
  from chainlit.cli import run_chainlit
176
  run_chainlit(__file__)