--- title: SurfMatch emoji: 🏄 colorFrom: blue colorTo: red sdk: gradio sdk_version: '5.9.1' app_file: app.py pinned: false --- # SurfMatch **Dataset:** Yoad22/surfmatch-dataset - 15,000 synthetic rider profiles, 150-board catalog **Embedding model:** sentence-transformers/all-mpnet-base-v2 - 768-dimensional embeddings **Generation model:** Qwen/Qwen3-1.7B - structured custom board spec + rationale **Space:** https://huggingface.co/spaces/Yoad22/surfmatch --- ## What This Is A surfboard recommendation app. Tell it your height, weight, skill level, current board, typical conditions, and what you're trying to achieve, and it returns the 3 closest-matching boards from a 150-board catalog, plus a 4th board that a small language model designs specifically for you, including dimensions, tail, fins, construction, and a written rationale. The app is built to also serve surfers who want to *change* styles, not just riders shopping within the style they already have. --- ## How It Works **1. Category** is decided from the rider's stated goal and skill level using a fixed rule, not from text similarity. Testing embeddings for this decision directly (see Key Results) showed they aren't reliable enough for it on their own. **2. Physical fit** combines two real sizing guidelines: heavier and less experienced riders need more volume, and taller and less experienced riders want relatively more length, each measured as a percentile within the board's own category (categories differ hugely in scale, so raw liters or feet aren't comparable across them). **3. Embedding similarity** (all-mpnet-base-v2) ranks boards within the already-correct category by how well a rider's profile matches each board's description - the comparison the model is demonstrably good at. **4. Diversity** picks the final 3 boards so they differ from each other on tail, fins, or construction, instead of returning 3 near-identical boards. **5. The 4th board** is generated by Qwen3-1.7B: given the rider's percentiles and the category's real dimension ranges, the model is asked to reason about the right sizing in words first, then commit to dimensions, tail, fins, construction, and a rationale, as structured JSON. It's explicitly allowed to make unconventional choices (e.g. quad fins on a longboard) that the fixed 150-board catalog doesn't offer. --- ## Key Results | Metric | Value | |---|---| | Boards in catalog | 150 | | Rider profiles generated | 15,000 | | Embedding model hit_rate@1 (vs. 20% random baseline) | 41.6% | | Embedding model hit_rate@3 (vs. 49% random baseline) | 45.0% | | Silhouette score by true category (PCA-50 space) | 0.053 | | Diversity: hit real per-category ceiling on tail | 100.0% | | Diversity: hit real per-category ceiling on fins | 97.3% | | Diversity: hit real per-category ceiling on construction | 96.3% | | Diversity: hit the ceiling on all three at once | 93.7% | | Custom board JSON parse rate | ~90% | The embedding model captures real signal about a rider's best-fit category (41.6% top-1 accuracy against a 20% random baseline), but that signal is not clean enough to decide the category on its own - the silhouette score of 0.053 confirms categories overlap heavily in embedding space. That's why category is decided by a fixed rule and embeddings are used only to rank within a category, where they change at least one of the three recommended boards for roughly half of all riders tested - real, independent work, not a no-op. --- ## An Honest Limitation The custom board generator's written reasoning (`sizing_reasoning`) explicitly and correctly describes how a rider's weight and height percentiles should affect the board's dimensions in nearly every case. But across three separate real experiments at 30-rider scale - raw numbers, percentile-grounded numbers, and percentile-grounded numbers with forced reasoning-before-numbers - the model's actual output dimensions barely correlated with weight or height (correlation near 0 each time), while skill-based sizing worked reliably and correctly (correlation consistently and correctly signed). In other words: this small model's stated reasoning is not fully faithful to what actually drives its numeric output. This is a genuine, tested limitation of a 1.7B-parameter model on this task, documented here rather than hidden - the skill-based sizing and the category/tail/fins/construction choices all work as intended. ---