Here's a concise, professional technical briefing for the personalized-recommender-course repository, written in the style of a senior AI engineer consultant report.
The Problem
This repository delivers a hands-on course for building a real-time personalized recommender for H&M fashion articles. It spans feature engineering, two-tower neural network training, MLOps via Hopsworks, KServe deployment, and a Streamlit web interface. While the scope is broad and the educational value is clear, the codebase shows several structural and quality concerns that would need addressing before it could safely power a production system.
What This Does
The repository implements a 5-module FTI (Feature/Training/Inference) architecture using Hopsworks Feature Store, two-tower embedding models, and vector-based real-time inference. Core workflows are concentrated in recsys/training/two_tower.py (23 functions, 8 types), recsys/inference/llm_ranking_predictor.py (6 functions, 2 classes), and recsys/ui/recommenders.py (9 functions). Data flows through recsys/features/ for preprocessing, recsys/hopsworks_integration/ for store interaction, and recsys/ui/ for the Streamlit frontend. The system reads H&M raw data, computes features, trains user/item embeddings, registers models, and serves recommendations via a KServe-backed online pipeline.
How It Is Wired
Execution starts at streamlit_app.py:103 (main), which reaches 37 downstream functions. The internal call graph shows 137 resolved call edges. Key entry points and their callers:
get_feature_storeβ called from 4 places; participates in a circular import withrecsys/hopsworks_integration/feature_store.pypredictβ called from 4 places; invoked viallm_recommendations -> should_show_item x3sampleβ called from 3 places; feedscompute_ranking_datasetshould_show_itemβ called from 3 places; called byllm_recommendations x3andcustomer_recommendations x2df_to_dsβ called from 2 places; used byget_train_val_splitget_modelβ called from 2 places; feedsdeploy -> get_model x2trackβ called from 2 places; invoked bydisplay_item x2anddisplay_llm_item x2
The most connected module is recsys/config (Ca=10, Ce=0, instability=0), followed by recsys/ui/recommenders (instability=0.8) and streamlit_app (instability=1, Ce=5). Two circular import cycles exist involving recsys/hopsworks_integration/__init__.py and recsys/hopsworks_integration/feature_store.py, which increases cognitive load when tracing dependencies.
The traced exit from the process goes through main -> customer_recommendations -> predict [model via self.llm.invoke], indicating the LLM-powered ranker makes an outbound model call. File I/O and network calls are limited but present: recsys/ui/utils.py opens files without a context manager, and several functions make network calls to Hopsworks.
How To Use It
Setup: This is a Python project. Install with pip install -e . or uv pip install -e . from the root, as pyproject.toml is present. No Dockerfile exists; local Python 3.x is the intended runtime.
Configuration: Environment variables and secrets are expected in .env.example. The .github/workflows/ml_pipelines.yaml workflow references secrets and has no permissions declaration and no timeout-minutes. The code-health audit confirms secret-shaped paths are present in assets/github_actions_secrets.png.
Running it: Start the Streamlit demo with streamlit run streamlit_app.py. The live demo is hosted at https://decodingml-hands-on-personalized-recommender.streamlit.app/ but runs in 0-cost mode, scaling to 0 instances during idle periods and requiring 1β2 minutes to warm on first interaction.
Real-World Use
This codebase is suited for learning, prototyping, and coursework. A practical scenario: a data science team clones the repo, populates the Hopsworks feature store with H&M interaction data, trains the two-tower model via the notebooks, and iterates on the LLM ranking logic in recsys/hopsworks_integration/llm_ranking_serving.py. The Streamlit app provides a quick UI for testing recommendations per user. Because no test suite exists, changes to feature engineering or model logic carry regression risk.
Code Health & Issues
The measured code health audit (5 findings, 0 critical) identifies:
- [HIGH] No test suite; 32 source files have no corresponding test files. Any change ships with no signal that existing behavior holds.
- [MEDIUM] Dependencies declared without a lockfile (
pyproject.tomlhas nouv.lockorrequirements.txtlock) β builds are non-reproducible across environments. - [MEDIUM] Broad exception handling in
tools/clean_hopsworks_resources.pyβ bareexceptswallows errors indiscriminately. - [MEDIUM] Duplicate 6-line blocks across
recsys/hopsworks_integration/llm_ranking_serving.py,ranking_serving.py, andtwo_tower_serving.pyβ 16 repeated blocks total. - [MEDIUM] Import cycle between
recsys/hopsworks_integration/__init__.pyandrecsys/hopsworks_integration/feature_store.py. - [LOW] File opened without context manager in
recsys/ui/utils.pyβ handle may leak on error. - [LOW] No Dependabot/Renovate configured; 2 manifest files exist but no update bot.
- [LOW] No dependency vulnerability scan in CI; no
dependency-review-actionorosv-scannergate.
Additional SDLC observations: no Dockerfile, no LICENSE committed (though one exists in the file structure), and GitHub Actions secrets are present in the repository tree.
The Bottom Line
This is a well-structured, educational repository that successfully walks through the lifecycle of building a real-time recommenderβfrom feature engineering to KServe deployment. The FTI architecture is clear, the notebooks are practical, and the Streamlit demo provides immediate feedback. However, the absence of tests, a lockfile, and CI dependency scanning means it is not production-ready without remediation. Teams looking to learn the full stack of a modern recommender system will get significant value; teams needing battle-hardened reliability should budget time to add test coverage, lock dependencies, and break the import cycles before promoting any branch to production.
Report generated by static analysis pipeline. All counts, file paths, and code evidence are drawn from the repository structure and import graph as-is.