Contexto
SportStats es mi trabajo de fin de grado. Es una plataforma web que reúne datos deportivos con un flujo de mensajes cortos parecido a X, donde los usuarios publican, y que recomienda contenido a cada usuario.
Es un proyecto que realicé yo solo y el código es público.
Datos
La plataforma se alimenta de dos fuentes. API-SPORTS aporta datos deportivos a través de su API, y los datos de atletismo se extraen de World Athletics con BeautifulSoup, con pandas para tratar los datos.
Las dos fuentes son externas y no las controlo, así que una caché en disco con caducidad limita el número de llamadas que se les hacen.
Los datos de la aplicación están en MySQL, con acceso mediante SQLAlchemy.
Recomendaciones
El contenido se recomienda con TF-IDF y k vecinos más cercanos, implementados en scikit-learn. TF-IDF convierte cada texto en un vector ponderado, y los vecinos se buscan con distancia coseno y búsqueda por fuerza bruta. El modelo ajustado se guarda con joblib, para no tener que construirlo de nuevo en cada arranque.
La distancia coseno compara la dirección de dos vectores y no su longitud, de modo que un mensaje largo y uno corto sobre el mismo tema pueden quedar cerca. Por eso encaja mejor con texto que una distancia euclídea simple.
La fuerza bruta da vecinos exactos y no necesita un índice que mantener sincronizado. Solo miraría un índice aproximado si el volumen de contenido lo pidiera.
Notas de ingeniería
El backend es Flask. Las cuentas y los formularios usan Flask-Login, Bcrypt para el hash de contraseñas y WTForms para la validación, y la interfaz está hecha con Bootstrap. Las contraseñas se guardan con hash y no en claro, y los datos de los formularios se validan en el servidor antes de usarse.
Resultado
El proyecto obtuvo una calificación de 10/10 con matrícula de honor.
Límites y qué haría después
El repositorio público no tiene pruebas automáticas ni CI. Es la carencia principal, y pesa más donde el comportamiento es delicado: la ingesta de datos y el recomendador.
Si volviera a él, empezaría por ahí, con pruebas de la salida del extractor y de las recomendaciones sobre un conjunto de datos pequeño y fijo, y un flujo de CI que las ejecute.