Context
SportStats is my final degree project. It is a web platform that brings sports data together with a micro-feed similar to X, where users publish short posts, and it recommends content to each user.
It was a project I carried out alone, and the code is public.
Data
The platform draws on two sources. API-SPORTS provides sports data through its API, and athletics data is scraped from World Athletics with BeautifulSoup, with pandas for handling the data.
Both sources are external and neither is under my control, so a disk cache with expiry limits the number of calls made to them.
The application data lives in MySQL, accessed through SQLAlchemy.
Recommendations
Content is recommended with TF-IDF and k-nearest neighbours, implemented in scikit-learn. TF-IDF turns each piece of text into a weighted vector, and the neighbours are found using cosine distance, with brute-force search. The fitted model is persisted with joblib, so it does not have to be built again on every start.
Cosine distance compares the direction of two vectors rather than their length, so a long post and a short one about the same subject can still end up close to each other. That is the reason it suits text better than a plain Euclidean distance.
Brute force gives exact neighbours and needs no index to keep in sync. I would only look at an approximate index if the volume of content called for it.
Engineering notes
The backend is Flask. Accounts and forms use Flask-Login, Bcrypt for password hashing and WTForms for validation, and the interface is built with Bootstrap. Passwords are hashed rather than stored, and form input is validated on the server before it is used.
Result
The project was graded 10/10 with honours.
Limits and what I would do next
The public repository has no automated tests and no CI. That is the main gap, and it matters most where the behaviour is subtle: the data ingestion and the recommender.
If I came back to it, I would start there, with tests for the scraper’s output and for the recommendations of a small fixed dataset, and a CI workflow to run them.