Skip to content

Capabilities

Practical API overview. Formal contracts: CONTRACTS.md.

Install & run

pip install streamlit-recommenders          # or, from a clone: pip install -e ".[dev]"
python -m streamlit_recommenders.data.prepare --dataset ml-latest-small # or ml-latest, ml-25m, ml-32m; add --with-posters (needs TMDB_API_KEY)
python examples/train_baseline_artifacts.py --data data/ml-latest-small # Additional training script for baseline models and exporting artifacts
SR_DATA_DIR=data/ml-latest-small streamlit run examples/compare_models_rows.py # 3 models comparison (in rows layout) library demonstration

Requires Python ≥3.10.

Keys (TMDB_API_KEY / TMDB_BEARER_TOKEN, KAGGLE_USERNAME / KAGGLE_KEY) and SR_DATA_DIR can go in a .env file (copy .env.example) or be set inline as above. The preparation CLI auto-loads .env; the example apps read SR_DATA_DIR from the shell (export it or pass it inline). .env keeps the showcase commands clean.

Public API

Area API
App sr.run(...)
Data load_items, load_interactions, load_users, load_dataset, load_dataset_from_paths, resolve_image_urls, Dataset, ColumnMap, validate_dataset
Data prep prepare_movielens, prepare_goodbooks, is_complete
Params slider, selectbox, param_value
Layouts rows, grid, cards
Session current_user, selected_items, disliked_items, displayed_items, selections
Content plot, table, markdown, markdown_file
Viz helpers dataset_info, recommendation_overlap_matrix, plot_overlap_heatmap, plot_metric_comparison, plot_ranked_items, plot_score_distribution
Metrics evaluate, hit_rate_at_k, recall_at_k, ndcg_at_k, mrr_at_k, coverage
Models BaseRecommender (subclass to define a model), ArtifactRecommender (load exported .npz)

sr.run()

sr.run(
    get_recommendations=fn_or_model_or_dict,
    items=items,
    interactions=train,
    layout="rows",
    params={"alpha": sr.slider("alpha", 0.0, 1.0, 0.5)},
    intro=lambda: sr.markdown("### Model contract"),
    body=lambda: sr.table(metrics),
)

Pass a dict for compare mode:

sr.run(get_recommendations={"Ours": ours, "EASE": ease}, items=items, interactions=train)

Compare mode shows one shared Get Recommendations button so all rows refresh against the same session profile.

Model-specific controls are keyed by recommender label:

sr.run(
    get_recommendations={"Ours": ours, "EASE": ease},
    items=items,
    interactions=train,
    params={"Ours": {"alpha": sr.slider("alpha", 0.0, 1.0, 0.5)}},
)

Data

dataset = sr.load_dataset_from_paths(
    items="items.csv",
    interactions="train_interactions.csv",
    users="users.csv",
    test="test_interactions.csv",
)

Default logical columns: user_id, item_id, rating, timestamp, title, image_url, description.

Only item_id is required for items. Movie demos should prefer title, image_url, and description; missing images render with a placeholder. Local protected datasets should live under data/ and stay out of git.

Load a prepared folder (resolves poster paths to local files) with:

items, train, test = sr.load_dataset("data/ml-latest-small")

Data preparation

Prepare datasets from inside the library (no standalone scripts required):

sr.prepare_movielens("ml-32m")                      # items.csv + interactions.csv
sr.prepare_movielens("ml-32m", with_posters=True)   # + TMDB descriptions/posters (TMDB_API_KEY)
sr.prepare_goodbooks()                              # books carry cover image URLs (kagglehub optional)

Or via CLI:

python -m streamlit_recommenders.data.prepare --dataset ml-32m --with-posters

Each prepared folder gets a dataset.json manifest; sr.is_complete(root) guards against re-running collection, so preparation is idempotent and a finished dataset is not re-fetched before a demo run. TMDB enrichment is robust (retry/backoff, 429 handling) and writes a metadata_completeness.csv report listing items still missing a poster or description.

External model training

The core package does not train heavy models. Train with any external code, export pure artifacts, then pass a function/object that returns ordered item ids:

def get_recommendations(user_id, k, session_items=None, **params):
    return trained_model.rank(user_id, session_items=session_items)[:k]

sr.run(
    get_recommendations={"Ours": get_recommendations, "EASE": ease_baseline},
    items=items,
    interactions=train,
)

One optional script trains the three default baseline families and exports NumPy artifacts:

.venv/bin/python examples/train_baseline_artifacts.py --data data/<dataset-name>
SR_DATA_DIR=data/<dataset-name> streamlit run examples/compare_models_rows.py

The script writes artifacts/itemknn.npz, artifacts/ease.npz, and artifacts/sequential_cf.npz. Each artifact contains item_ids, weights, and popularity; the demo loads only these arrays and never imports the training code.

Reference baselines are defined in examples/reference_recommenders.py (subclassing BaseRecommender), not shipped by the library — copy one as a starting point:

Family Reference class Use
ItemKNN ItemKNNRecommender classic item-item CF baseline
EASE EASERecommender strong shallow linear implicit-feedback baseline
Sequential CF SequentialCFRecommender timestamped next-item baseline (first-order item transitions)

Item cards and layouts

  • rows: one horizontal row with fixed-width clickable poster cards and side scroll.
  • grid: wrapped clickable poster gallery for catalog-style browsing.
  • cards: swipe deck. One card at a time with Like / Dislike / Skip buttons.
  • Clickable layouts (rows, grid): selected items stay in place as greyed cards; click again to unselect.
  • Compare mode always uses rows.

Swipe deck (cards)

Like adds the item to the session profile (same signal as a card click); Dislike records negative feedback and removes the card; Skip just advances. After swipes_per_refresh like/dislike swipes the queue is refreshed against the updated profile:

sr.run(get_recommendations=model, items=items, interactions=train, layout="cards", swipes_per_refresh=5)

swipes_per_refresh defaults to 5 and can also be overridden via a reserved sidebar param. Swipe is single-model; compare mode (dict input) stays on rows.

Metrics

metrics = sr.evaluate(
    {"Ours": {0: [1, 2, 3]}},
    test_interactions=test,
    k=10,
    all_item_ids=items.item_id,
)
sr.table(metrics)
sr.plot_metric_comparison(metrics)

Dataset Inspection

sr.dataset_info(items, train)

The reusable dataset block shows headline metrics (item/user/interaction counts, matrix density) and a tabbed switcher over distribution plots — item genres (default), interactions per user, interactions per item (popularity long tail), rating distribution, and categorical item metadata. The tabs and chart styling match the results-inspection plots for a consistent look.

Recommendation Agreement

overlap = sr.recommendation_overlap_matrix({"ItemKNN": [1, 2, 3], "EASE": [2, 3, 4]})
sr.plot_overlap_heatmap(overlap, title="Top-k recommendation overlap")

The overlap helper computes pairwise Jaccard agreement between model outputs and renders it as a compact heatmap for compare-mode demos.

Examples

File Shows
reference_recommenders.py Way 2: define models by subclassing BaseRecommender (ItemKNN/EASE/SeqCF), fit in memory, and compare
compare_models_rows.py Lead demo (way 1): compare ItemKNN, EASE, and Sequential CF artifacts in rows layout
swipe_deck_cards.py Single-model swipe deck (cards layout) with like/dislike/skip; wraps EASE in a feedback-aware model that uses dislikes as a negative signal
compare_models_grid.py Grid layout with a sidebar model selector (one artifact at a time)
train_baseline_artifacts.py Train/export SciPy/NumPy baseline artifacts on a local data/<dataset-name> folder

Not yet implemented

  • Polars backend
  • UI file upload for models
  • Optional wrappers/examples for RecBole / RecPack / LensKit