Spaces:
Build error
Build error
File size: 11,723 Bytes
ce639d9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# -*- coding: utf-8 -*-
"""Simulador_POC_UNAD_ECBTI_JHON_GONZALEZ.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/18fQIhC6QTMEcoQY202hGIb2BH220X-PJ
"""
import pandas as pd
import ipywidgets as widgets
from IPython.display import display, clear_output, Markdown, Image
from google.colab import files
import os
# ============================
# Información de Autoría
# ============================
AUTHOR_INFO = """
**Autor:** Jhon Fredy González
**Programa:** ECBTI (Escuela de Ciencias Básicas, Tecnologías e Ingenierías)
**Institución:** UNAD (Universidad Nacional Abierta y a Distancia)
**Centro:** CIP (Centro de Innovación y Productividad) Dosquebradas
"""
LOGO_PATH = "/content/LOGOCIPDOQUEBRADAS.png"
# ============================
# Título y Descripción
# ============================
TITLE = "# 📚 Simulador de Pruebas UNAD 📚\n\n## **Exclusivamente para Directores de Curso**"
DESCRIPTION = """
Este simulador está diseñado para ayudar a los directores de curso a probar y validar preguntas en el formato F-7-4-2 de la UNAD.
Por favor, complete el formulario de registro antes de continuar.
"""
# ============================
# Variables Globales
# ============================
user_data_file = "user_data.xlsx" # Archivo para guardar los datos de los usuarios
visit_counter_file = "visit_counter.txt" # Archivo para contar las visitas
visit_count = 0 # Contador de visitas inicializado en 0
PASSWORD = "9870548" # Contraseña para descargar el archivo
# ============================
# Función para Registrar Datos
# ============================
def register_user_info():
"""
Muestra un formulario para registrar información del usuario.
"""
global visit_count
# Incrementar el contador de visitas
visit_count += 1
save_visit_counter()
display(Markdown("### Formulario de Registro"))
# Crear widgets para el registro
name_input = widgets.Text(description="Nombre:")
document_input = widgets.Text(description="Documento:")
course_code_input = widgets.Text(description="Código Curso:")
course_name_input = widgets.Text(description="Nombre Curso:")
evaluation_type_input = widgets.Text(description="Tipo Evaluación:")
submit_button = widgets.Button(description="Enviar Registro ✅")
def on_submit_clicked(b):
# Guardar la información ingresada
global user_info
user_info = {
"Nombre": name_input.value,
"Documento": document_input.value,
"Código Curso": course_code_input.value,
"Nombre Curso": course_name_input.value,
"Tipo Evaluación": evaluation_type_input.value
}
# Guardar los datos del usuario en un archivo Excel
save_user_data(user_info)
# Limpiar la salida y mostrar mensaje de confirmación
clear_output(wait=True)
display(Markdown(f"### ¡Registro Exitoso! ✅"))
display(Markdown(f"- **Nombre:** {user_info['Nombre']}"))
display(Markdown(f"- **Documento:** {user_info['Documento']}"))
display(Markdown(f"- **Código Curso:** {user_info['Código Curso']}"))
display(Markdown(f"- **Nombre Curso:** {user_info['Nombre Curso']}"))
display(Markdown(f"- **Tipo Evaluación:** {user_info['Tipo Evaluación']}"))
# Mostrar el número de la visita
display(Markdown(f"--- Esta es la **visita número {visit_count}** ---"))
# Continuar con el quiz
questions = load_questions_from_excel()
display_question(0, questions)
# Mostrar los widgets y el botón
display(name_input)
display(document_input)
display(course_code_input)
display(course_name_input)
display(evaluation_type_input)
display(submit_button)
# Asociar la función al botón
submit_button.on_click(on_submit_clicked)
# ============================
# Funciones Principales
# ============================
def load_questions_from_excel():
"""
Permite al usuario cargar un archivo Excel y lo convierte en una lista de preguntas.
"""
display(Markdown("**Nota Importante:**"))
display(Markdown("- El archivo Excel **debe estar en el formato F-7-4-2 de la UNAD**."))
display(Markdown("- **No debe incluir encabezados** y debe tener al menos 16 columnas."))
display(Markdown("- El archivo debe estar en formato **`.xlsx`**, no en formato `.xls` (versión antigua de Excel)."))
print("Cargando archivo Excel...")
uploaded = files.upload()
# Verificar que se haya cargado exactamente un archivo
if len(uploaded.keys()) != 1:
raise ValueError("Debe cargar exactamente un archivo.")
filename = list(uploaded.keys())[0]
try:
# Validar que el archivo tenga la extensión .xlsx
if not filename.endswith(".xlsx"):
raise ValueError("El archivo debe estar en formato `.xlsx`. Por favor, use un archivo moderno de Excel.")
# Leer el archivo Excel sin encabezados
df = pd.read_excel(filename, header=None)
# Eliminar el archivo cargado para liberar espacio
os.remove(filename)
# Verificar que el archivo tenga suficientes columnas
if df.shape[1] < 16:
raise ValueError("El archivo no tiene el formato esperado. Debe tener al menos 16 columnas.")
# Seleccionar solo las columnas relevantes (usando índices numéricos)
df = df.iloc[:, [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]]
# Renombrar columnas para facilitar el acceso
df.columns = [
"ENUNCIADO",
"CLAVE",
"OPCIÓN_DE_RESPUESTA_A",
"REALIMENTACIÓN_A",
"OPCIÓN_DE_RESPUESTA_B",
"REALIMENTACIÓN_B",
"OPCIÓN_DE_RESPUESTA_C",
"REALIMENTACIÓN_C",
"OPCIÓN_DE_RESPUESTA_D",
"REALIMENTACIÓN_D"
]
# Convertir todos los valores a cadenas de texto y reemplazar NaN con cadenas vacías
df = df.astype(str).replace("nan", "")
return df.to_dict(orient="records")
except Exception as e:
# Si ocurre un error, asegurarse de eliminar el archivo cargado
if os.path.exists(filename):
os.remove(filename)
raise e
def display_question(index, questions):
"""
Muestra una pregunta específica con opciones de respuesta.
"""
global current_question_index
current_question_index = index
question = questions[index]
# Mostrar la pregunta con formato matemático
display(Markdown(f"--- Pregunta {index + 1} --- 📝"))
display(Markdown(question["ENUNCIADO"]))
display(Markdown("\n**Opciones:**"))
options = {
"A": question["OPCIÓN_DE_RESPUESTA_A"],
"B": question["OPCIÓN_DE_RESPUESTA_B"],
"C": question["OPCIÓN_DE_RESPUESTA_C"],
"D": question["OPCIÓN_DE_RESPUESTA_D"]
}
for key, value in options.items():
if value.strip(): # Solo mostrar opciones no vacías
display(Markdown(f"{key}) {value}"))
# Widget para seleccionar la respuesta
radio_buttons = widgets.RadioButtons(
options=["A", "B", "C", "D"],
description="Respuesta:",
disabled=False
)
submit_button = widgets.Button(description="Enviar Respuesta ✅")
def on_submit_clicked(b):
selected_answer = radio_buttons.value
correct_answer = question["CLAVE"]
# Obtener la retroalimentación correspondiente
feedback = ""
if selected_answer == "A":
feedback = question["REALIMENTACIÓN_A"]
elif selected_answer == "B":
feedback = question["REALIMENTACIÓN_B"]
elif selected_answer == "C":
feedback = question["REALIMENTACIÓN_C"]
elif selected_answer == "D":
feedback = question["REALIMENTACIÓN_D"]
# Mostrar retroalimentación
clear_output(wait=True)
if selected_answer == correct_answer:
display(Markdown(f"\n**¡Correcto! ✅ {feedback}**"))
else:
display(Markdown(f"\n**¡Incorrecto! ❌ {feedback}**"))
# Botón para avanzar a la siguiente pregunta
if index < len(questions) - 1:
next_button = widgets.Button(description="Siguiente Pregunta ➡️")
display(next_button)
next_button.on_click(lambda b: display_question(index + 1, questions))
else:
display(Markdown("\n**🎉 ¡Has completado todas las preguntas! 🎉**"))
display(radio_buttons)
display(submit_button)
submit_button.on_click(on_submit_clicked)
# ============================
# Funciones para Guardar Datos
# ============================
def save_user_data(user_info):
"""
Guarda los datos del usuario en un archivo Excel.
"""
try:
# Si el archivo ya existe, leerlo
if os.path.exists(user_data_file):
df = pd.read_excel(user_data_file)
else:
# Crear un DataFrame vacío si el archivo no existe
df = pd.DataFrame(columns=["Nombre", "Documento", "Código Curso", "Nombre Curso", "Tipo Evaluación"])
# Agregar los nuevos datos
new_row = pd.DataFrame([user_info])
df = pd.concat([df, new_row], ignore_index=True)
# Guardar el archivo
df.to_excel(user_data_file, index=False)
except Exception as e:
print(f"Error al guardar los datos del usuario: {e}")
def save_visit_counter():
"""
Guarda el contador de visitas en un archivo de texto.
"""
global visit_count
try:
# Si el archivo ya existe, leer el contador
if os.path.exists(visit_counter_file):
with open(visit_counter_file, "r") as f:
visit_count = int(f.read().strip() or 0)
# Incrementar el contador
visit_count += 1
# Guardar el contador en el archivo
with open(visit_counter_file, "w") as f:
f.write(str(visit_count))
except Exception as e:
print(f"Error al guardar el contador de visitas: {e}")
def download_user_data_with_password():
"""
Descarga el archivo Excel con los datos de los usuarios después de verificar la contraseña.
"""
password_input = widgets.Password(description="Contraseña:")
download_button = widgets.Button(description="Descargar Registros 🔒")
output = widgets.Output()
def on_download_clicked(b):
with output:
if password_input.value == PASSWORD:
if os.path.exists(user_data_file):
files.download(user_data_file)
display(Markdown("### 📥 Archivo descargado exitosamente: `user_data.xlsx`"))
else:
display(Markdown("### ❌ No hay datos disponibles para descargar."))
else:
display(Markdown("### ❌ Contraseña incorrecta. Inténtalo de nuevo."))
download_button.on_click(on_download_clicked)
display(password_input, download_button, output)
# ============================
# Ejecución Principal
# ============================
if __name__ == "__main__":
# Mostrar el logo
display(Image(filename=LOGO_PATH, width=300))
# Mostrar la información de autoría
display(Markdown(TITLE))
display(Markdown(AUTHOR_INFO))
# Mostrar la descripción
display(Markdown(DESCRIPTION))
# Botón para descargar los datos con contraseña
display(Markdown("### Para el creador: Usa el botón a continuación para descargar los registros."))
download_user_data_with_password()
# Registrar la información del usuario
register_user_info() |