A Flask + React app that suggests board games using classical IR and LLM-powered query enhancement, with transparent explanations of why each game was recommended.
- TF-IDF cosine similarity — baseline keyword retrieval
- Truncated SVD (LSA) — latent semantic retrieval that captures themes beyond exact keywords
- AI query rewriting — an LLM rewrites your query based on the latent dimensions it activates, surfacing games you might not have thought to search for
- AI summary — after both searches run, the LLM writes a unified narrative: which themes fired, top picks from each search, and one overall recommendation
- Free-text queries — e.g.
strategic medieval war game with no dice - Seed-title recommendations — pick a game and get semantically similar games
- Combined input — seed game + clarifying details (e.g. similar to Catan, but shorter and card-based)
- Latent dimension explainability — every result shows which SVD themes drove the match
| Layer | Tech |
|---|---|
| Backend | Flask, Flask-SQLAlchemy |
| Frontend | React + TypeScript + Vite |
| IR / ML | scikit-learn (TfidfVectorizer, TruncatedSVD) |
| LLM | Spark API (infosci_spark_client) |
| Data | SQLite (data/database.sqlite) |
- User provides a seed game, a text query, or both.
- The backend projects the input into TF-IDF and SVD spaces and returns the top-K games by cosine similarity (standard results).
- If
SPARK_API_KEYis set, the top activated SVD dimensions are fed to the LLM, which rewrites the query to focus on the most semantically relevant vocabulary. The rewritten query runs through the same retrieval pipeline (AI-enhanced results). - A second LLM call synthesises both result sets into a plain-English summary with bullet-pointed top picks and an overall recommendation.
FlavorMatrix/
├── src/
│ ├── app.py
│ ├── routes.py
│ ├── models.py
│ └── services/
│ ├── index_store.py
│ ├── ir.py
│ └── query_rewriter.py # rewrite_query + generate_summary
├── scripts/
│ └── build_indices.py
├── frontend/
│ └── src/
│ ├── App.tsx # SummaryPanel + two-column results
│ ├── App.css
│ ├── Landing.tsx
│ └── types.ts
├── data/
│ ├── database.sqlite # not tracked in git (too large)
│ └── artifacts/ # generated by build_indices.py
├── requirements.txt
└── README.md
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtpython3 scripts/build_indices.pyGenerates under data/artifacts/:
tfidf_matrix.npz, tfidf_vectorizer.pkl, svd_model.pkl, svd_embeddings.npy, games.json, game_ids.json, svd_top_terms.json
cd frontend
npm install
npm run build
cd ..python3 src/app.pyOpen http://localhost:5001.
Set SPARK_API_KEY in your environment before starting the server. Without it the app runs standard IR only and the AI summary and rewritten query are skipped.
export SPARK_API_KEY=your_key_here
python3 src/app.py| Endpoint | Method | Description |
|---|---|---|
/api/config |
GET | Returns {"use_llm": bool} |
/api/games/search?q= |
GET | Autocomplete game title search |
/api/recommendations |
GET | Standard IR results (q, seed, method, k) |
/api/rag |
GET | Standard + AI-enhanced results + LLM summary |
/api/latent-dimensions |
GET | Corpus-wide SVD dimension stats |
/api/games/dimensions?id= |
GET | Top SVD dimensions for a specific game |
/api/metrics |
GET | Cached evaluation metrics + feedback score |
/api/feedback |
POST | Record thumbs-up/down on a result |
{
"original_label": "Similar to Catan + details",
"original_dims": [...],
"original_results": [...],
"rewritten_query": "resource trading card game fast settlement building",
"rewritten_dims": [...],
"rag_results": [...],
"llm_summary": "Your search activated themes of resource trading...",
"error": null
}Games included in the index:
type = 'boardgame'users_rated > 50
Combined text field: description + boardgamecategory + boardgamemechanic (HTML-unescaped, whitespace-normalised).
npm run build # builds frontend
npm run start # starts Flask server
npm run prepare-data # runs build_indices.pydata/database.sqliteis git-ignored (exceeds GitHub's file size limit). Rebuild artifacts from a local copy of the database before deploying.- The AI summary makes two sequential LLM calls per query (rewrite + summary). Expect ~2–4 s added latency when
SPARK_API_KEYis set.