Spaces:
Sleeping
title: Sonix ML API
emoji: π
colorFrom: blue
colorTo: indigo
sdk: docker
pinned: false
SONIX RUSH AI β Running Shoes Recommender Engine
SONIX RUSH AI is a specialized machine learning inference service designed for the SONIX RUSH application. It implements a Hybrid Recommendation System that combines Content-Based Filtering (via Deep Autoencoders and K-Means Clustering) with Collaborative Filtering (User-Based KNN) to deliver personalized running shoe recommendations.
This engine operates as a standalone inference service and communicates with the core backend and frontend via RESTful APIs.
Table of Contents
- System Overview
- Architecture
- Technology Stack
- Project Structure
- Installation Guide
- Configuration
- Usage Guide
- API Documentation
- Continuous Training
- Error Handling
- Docker Deployment
- Testing
- Contributing
- License
System Overview
The SONIX RUSH AI engine isolates high-computational ML workloads from the primary transactional backend. Running as an independent service ensures that model inference and data processing do not impact the performance of the main application.
| Property | Detail |
|---|---|
| Integration Method | REST API |
| Methodology | Hybrid β Content-Based + Collaborative (separate pipelines) |
| Optimization | In-Memory Micro-Caching with TTL (60s) |
| Continuous Training | Background CF refresh every 50 interactions |
| Deployment | Docker / Hugging Face Spaces |
Architecture
The system uses two independent recommendation pipelines, each serving a different use case.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SONIX RUSH AI Engine β
β β
β βββββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββ β
β β Content-Based Pipeline β β Collaborative Pipeline β β
β β POST /recommend/road β β POST /interact β β
β β POST /recommend/trail β β GET /recommend/feed β β
β β β β β β
β β 1. Map user questionnaire β β 1. Receive interaction β β
β β β numerical vector β β 2. Real-time inject β β
β β 2. Encode β 8D Latent Space β β into user vector β β
β β (Deep Autoencoder) β β 3. KNN: find similar β β
β β 3. Route to nearest clusters β β users (cosine) β β
β β (K-Means, top βK/3β) β β 4. Weighted score β β
β β 4. Masked Cosine Similarity β β aggregation β β
β β 5. Return Top 10 shoes β β 5. Return Top 20 shoes β β
β βββββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββ β
β β
β FastAPI + Uvicorn (4 workers) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
SONIX RUSH Backend SONIX RUSH Frontend
(REST calls) (REST calls)
Content-Based: Training Pipeline (Offline)
Supabase β fetch_shoes_by_type() β MinMaxScaler
β Deep Autoencoder (300 epochs, batch=64)
β K-Means (K=5, n_init=20) on 8D latent space
β Save versioned artifacts to model_artifacts/{type}/v_{timestamp}/
Content-Based: Inference Pipeline (Online)
User Questionnaire β Heuristic Feature Mapping β Numerical Vector
β Encoder β 8D Latent Vector
β K-Means: select top βK/3β nearest clusters
β Masked Cosine Similarity on candidate pool
β Top 10 shoes
Feature masking ensures similarity is computed only on features the user explicitly provided, preventing noise from neutral default values.
Collaborative Filtering Pipeline (Real-Time)
POST /interact β Real-Time Injection into user vector
β User-Based KNN (cosine, brute force, sparse CSR matrix)
β Weighted score aggregation from k neighbors
β Filter seen items β Enrich with shoe metadata
β Top 20 shoes (TTL-cached 60s per user)
β Background CT trigger every 50 interactions
Autoencoder Architecture
Input (N-dim)
β Dense(32) + BatchNorm + Dropout(0.3) β Encoder
β Dense(16) + BatchNorm + Dropout(0.3) β Encoder
β Dense(8) + BatchNorm + Dropout(0.3) β Latent Space (saved as shoe_encoder.h5)
β Dense(16) + BatchNorm + Dropout(0.3) β Decoder
β Dense(32) + BatchNorm + Dropout(0.3) β Decoder
β Dense(N, sigmoid) β Reconstruction Output
Loss: MSE | Optimizer: Adam (lr=0.001) | Metric: MAE
Technology Stack
Core & Backend
| Library | Version | Purpose |
|---|---|---|
| Python | 3.11 | Primary language β strict version required for TensorFlow 2.15.0 |
| FastAPI | 0.129.0 | High-performance async web framework |
| Uvicorn | 0.40.0 | ASGI web server |
| Gunicorn | 25.1.0 | Process manager |
| Pydantic | 2.12.5 | Request/response schema validation |
| ujson | 5.11.0 | High-speed JSON serialization (UJSONResponse) |
Machine Learning & Data Science
| Library | Version | Purpose |
|---|---|---|
| TensorFlow / Keras | 2.15.0 | Deep Autoencoder for latent space projection |
| Scikit-Learn | 1.5.2 | K-Means Clustering and User-Based KNN |
| Pandas | 2.2.2 | Data manipulation and user-item pivot matrix |
| NumPy | 1.26.4 | Numerical computation and vector operations |
| SciPy | 1.13.1 | Sparse CSR matrix for memory-efficient CF |
Database & Infrastructure
| Library | Version | Purpose |
|---|---|---|
| Supabase | 2.27.3 | PostgreSQL-based Backend-as-a-Service |
| HTTPX | 0.28.1 | Async HTTP client |
| python-dotenv | 1.0.1 | Environment variable management |
| Docker | latest | Containerization |
Testing & Quality Assurance
| Library | Version | Purpose |
|---|---|---|
| Pytest | 8.0.2 | Unit and integration testing |
| pytest-mock | 3.12.0 | Supabase client mocking in CI |
| pytest-asyncio | 0.23.5 | Async test support |
| Locust | 2.24.0 | Load testing and benchmarking |
| Flake8 | 7.0.0 | Code linting |
Project Structure
sonix-ml/
β
βββ src/
β βββ main.py # FastAPI app, lifespan, all endpoints
β βββ config.py # ROAD_FEATURES and TRAIL_FEATURES definitions
β βββ database.py # Supabase client, interaction aggregation, upsert logic
β β
β βββ recommender/
β β βββ content_based.py # Core pipeline: cluster routing + masked cosine similarity
β β βββ road_recommender.py # Road heuristic mapping + pipeline wrapper
β β βββ trail_recommender.py # Trail heuristic mapping + pipeline wrapper
β β βββ collaborative_filtering.py # UserCollaborativeRecommender (UBCF + TTL cache)
β β
β βββ training/
β βββ architecture.py # Deep Autoencoder definition (build_autoencoder)
β βββ training_engine.py # Full training orchestration (run_training)
β
βββ model_artifacts/
β βββ road/
β β βββ v_YYYYMMDD_HHMMSS/ # Versioned β latest selected automatically on startup
β β βββ shoe_encoder.h5
β β βββ kmeans_model.pkl
β β βββ scaler.pkl
β β βββ shoe_features.pkl
β β βββ shoe_metadata.pkl
β βββ trail/
β βββ v_YYYYMMDD_HHMMSS/ # Same structure as road
β
βββ data/
β βββ road_dataset.csv
β βββ trail_dataset.csv
β βββ unused-data/ # Archived previous dataset versions
β
βββ notebooks/
β βββ data-preparation/
β βββ data-preparation-v2/
β βββ data-preparation-v3/
β βββ modelling/ # road_ml.ipynb, trail_ml.ipynb
β
βββ tests/
β βββ conftest.py # Auto-mocks Supabase for all tests
β βββ test_data_processing.py # Rating conversion + DB error handling
β βββ test_recommender_logic.py # Heuristic mapping + priority logic
β
βββ .github/workflows/
β βββ ci-ml.yml # Continuous Integration (lint + test)
β βββ cd-ml.yml # Continuous Deployment
β βββ ct-ml.yml # Continuous Training trigger
β
βββ locustfile.py
βββ Dockerfile
βββ requirements.txt # Production dependencies (all pinned)
βββ requirements-dev.txt # Dev/test dependencies
βββ README.md
Installation Guide
Prerequisites
- Python 3.11 (strictly required)
- Git
1. Clone the Repository
git clone https://github.com/SONIX-Kelompok-6/sonix-ml
cd sonix-ml
2. Set Up a Virtual Environment
Windows (PowerShell):
py -3.11 -m venv env
.\env\Scripts\activate
macOS / Linux:
python3.11 -m venv env
source env/bin/activate
3. Install Dependencies
Production:
pip install -r requirements.txt
Development (includes testing and linting tools):
pip install -r requirements-dev.txt
Configuration
Create a .env file in the root directory:
cp .env.example .env
Then populate it with your credentials:
SUPABASE_URL=https://your-project-id.supabase.co
SUPABASE_KEY=your-anon-public-key
Environment Variables Reference
| Variable | Required | Description |
|---|---|---|
SUPABASE_URL |
β Yes | Your Supabase project URL |
SUPABASE_KEY |
β Yes | Supabase anon/public API key |
π Never commit
.envto version control. Only.env.example(with placeholder values) should be committed.
Usage Guide
1. Training Pipeline (Offline)
Before starting the API, model artifacts must be generated. This step fetches shoe catalog data from Supabase, trains the Deep Autoencoders, runs K-Means Clustering, and serializes all artifacts with a versioned timestamp.
python -m src.training.training_engine
The engine runs sequentially for both categories:
>>> Initializing training sequence for: ROAD
>>> Initializing training sequence for: TRAIL
Artifacts are saved to versioned directories:
model_artifacts/
βββ road/v_YYYYMMDD_HHMMSS/
βββ trail/v_YYYYMMDD_HHMMSS/
Generated files per category:
| File | Description |
|---|---|
shoe_encoder.h5 |
Encoder model β projects features to 8D latent space |
kmeans_model.pkl |
K-Means (K=5) β routes inputs to candidate clusters |
scaler.pkl |
MinMaxScaler β must be used for inference normalization |
shoe_features.pkl |
Scaled feature matrix β used for cosine similarity at inference |
shoe_metadata.pkl |
DataFrame with cluster labels + column type definitions |
β οΈ The API will fail to start if artifacts are missing. Always run training before launching the server.
π‘ The API automatically selects the latest versioned directory on startup β no manual version management required.
2. Starting the API (Online)
Once artifacts are generated, launch the FastAPI server:
python -m src.main
The server starts at http://0.0.0.0:7860 with 4 Uvicorn workers. On startup, the server loads both artifact sets and initializes the CF engine from Supabase interaction data.
API Documentation
Interactive documentation is available at runtime:
- Swagger UI:
http://127.0.0.1:7860/docs - ReDoc:
http://127.0.0.1:7860/redoc
Visiting / auto-redirects to /docs.
GET /health
Returns service health and Continuous Training sync progress.
Response 200 OK:
{
"status": "healthy",
"ct_sync_progress": "12/50"
}
POST /recommend/road
Returns Top 10 road shoe recommendations via the Content-Based pipeline. All fields are optional β unset fields are excluded from similarity calculation via feature masking.
Request Body:
{
"pace": "Fast",
"arch_type": "Normal",
"strike_pattern": "Mid",
"foot_width": "Regular",
"season": "Summer",
"orthotic_usage": "No",
"running_purpose": "Race",
"cushion_preferences": "Firm",
"stability_need": "Neutral"
}
Request Body Fields:
| Field | Accepted Values |
|---|---|
pace |
"Easy", "Steady", "Fast" |
arch_type |
"Flat", "Normal", "High" |
strike_pattern |
"Heel", "Mid", "Forefoot" |
foot_width |
"Narrow", "Regular", "Wide" |
season |
"Summer", "Spring & Fall", "Winter" |
orthotic_usage |
"Yes", "No" |
running_purpose |
"Daily", "Tempo", "Race" |
cushion_preferences |
"Soft", "Balanced", "Firm" |
stability_need |
"Neutral", "Guided" |
Response 200 OK:
{
"status": "success",
"data": [
{
"shoe_id": "R045",
"name": "Nike Vaporfly 3",
"brand": "Nike",
"cluster": 2,
"match_score": 0.97
}
]
}
POST /recommend/trail
Returns Top 10 trail shoe recommendations. Uses trail-specific heuristics for terrain, traction, lug depth, and water resistance.
Request Body:
{
"pace": "Steady",
"arch_type": "Normal",
"strike_pattern": "Mid",
"foot_width": "Regular",
"season": "Summer",
"orthotic_usage": "No",
"terrain": "Rocky",
"rock_sensitive": "Yes",
"water_resistance": "Water Repellent"
}
Request Body Fields:
| Field | Accepted Values |
|---|---|
pace |
"Easy", "Steady", "Fast" |
arch_type |
"Flat", "Normal", "High" |
strike_pattern |
"Heel", "Mid", "Forefoot" |
foot_width |
"Narrow", "Regular", "Wide" |
season |
"Summer", "Spring & Fall", "Winter" |
orthotic_usage |
"Yes", "No" |
terrain |
"Light", "Mixed", "Rocky", "Muddy" |
rock_sensitive |
"Yes", "No" |
water_resistance |
"Waterproof", "Water Repellent" |
Response 200 OK:
{
"status": "success",
"data": [
{
"shoe_id": "T012",
"name": "Hoka Speedgoat 5",
"brand": "Hoka",
"cluster": 4,
"match_score": 0.94
}
]
}
POST /interact
Records a user interaction (Like or Rating) and immediately returns personalized CF recommendations via Real-Time Injection β the new interaction is injected into the user's vector before running KNN, so results reflect the latest signal without waiting for a full rebuild.
Also triggers a background CT refresh every 50 interactions (see Continuous Training).
Request Body:
{
"user_id": 8,
"shoe_id": "R278",
"action_type": "like",
"value": null
}
Request Body Fields:
| Field | Type | Required | Description |
|---|---|---|---|
user_id |
integer |
β Yes | Interacting user's ID |
shoe_id |
string |
β Yes | Target shoe ID (R prefix = road, T prefix = trail) |
action_type |
string |
β Yes | "like" or "rate" |
value |
integer |
Conditional | Star rating 1β5. Required when action_type is "rate" |
Interaction Score Mapping:
| Signal | Converted Score |
|---|---|
| Like | +1.0 |
| Rate 5β | +2.0 |
| Rate 4β | +1.0 |
| Rate 3β | +0.1 (neutral) |
| Rate 2β | -1.0 |
| Rate 1β | -2.0 |
If a user has both liked and rated the same shoe, scores are summed for higher confidence.
Response 200 OK:
{
"status": "success",
"data": [
{
"shoe_id": "R145",
"name": "ASICS Gel-Kayano 31",
"brand": "ASICS",
"match_score": 1.84
}
]
}
GET /recommend/feed/{user_id}
Returns a personalized shoe feed from the CF engine. Served from the 60-second TTL cache if available, otherwise computed fresh.
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
user_id |
integer |
β Yes | Target user's ID |
Example Request:
GET /recommend/feed/8
Response 200 OK:
{
"status": "success",
"data": [
{
"shoe_id": "R278",
"name": "Nike Pegasus 41",
"brand": "Nike",
"match_score": 2.31
}
]
}
Response 404 Not Found β cold-start user with no interaction history.
Continuous Training
Every 50 new interactions received via POST /interact, a non-blocking background task is dispatched that:
- Fetches fresh interaction data from Supabase (
favorites+reviewstables) - Rebuilds
UserCollaborativeRecommenderfrom the updated data - Hot-swaps the global
cf_enginewith zero downtime
The API response is returned immediately β the rebuild happens in the background. Progress is visible in /health via ct_sync_progress.
Error Handling
All error responses follow a consistent format:
{
"detail": "Human-readable error message."
}
| Status Code | Meaning | Common Cause |
|---|---|---|
200 OK |
Success | β |
404 Not Found |
Resource not found | Cold-start user with no interaction history |
422 Unprocessable Entity |
Validation error | Missing or invalid request fields |
500 Internal Server Error |
Unexpected error | Check server logs |
503 Service Unavailable |
Engine not ready | Run training pipeline first |
Docker Deployment
This service is containerized and compatible with Hugging Face Spaces and standard Docker environments.
Build and Run
docker build -t sonix-ml .
docker run -p 7860:7860 --env-file .env sonix-ml
The service will be accessible at http://localhost:7860.
Docker Compose (Optional)
version: "3.9"
services:
rush-ai:
build: .
ports:
- "7860:7860"
env_file:
- .env
restart: unless-stopped
docker compose up --build
Testing
Unit & Integration Tests
conftest.py automatically mocks the Supabase client across all tests, preventing real network calls during CI.
# Run all tests
pytest
# With verbose output and coverage report
pytest -v --tb=short --cov=src --cov-report=term-missing
Test coverage:
| File | What it tests |
|---|---|
test_data_processing.py |
Rating-to-score conversion, empty DataFrame handling from DB |
test_recommender_logic.py |
Heuristic priority mapping, fallback defaults, multi-source priority |
Load Testing
locust -f locustfile.py
Open http://localhost:8089 to configure and launch. Default scenario:
| Endpoint | Weight | Description |
|---|---|---|
POST /interact |
3Γ | Heaviest endpoint β simulates likes and ratings |
GET /recommend/feed/{user_id} |
1Γ | Feed retrieval |
GET /health |
1Γ | Lightweight health probe |
Load Test Results
Total requests: 10,420 across all endpoints β 0 failures (0% error rate). Aggregated throughput: 65.5 RPS.
Request Statistics
| Method | Endpoint | # Requests | Median (ms) | Avg (ms) | Min (ms) | Max (ms) | RPS |
|---|---|---|---|---|---|---|---|
| GET | /health |
2,052 | 4 | 27.6 | 2 | 3,014 | 14.3 |
| POST | /interact |
6,218 | 23 | 46.93 | 10 | 3,173 | 39.1 |
| GET | /recommend/feed/8 |
2,150 | 7 | 37.36 | 3 | 2,146 | 12.1 |
| Aggregated | 10,420 | 19 | 41.15 | 2 | 3,173 | 65.5 |
Response Time Percentiles
| Method | Endpoint | p50 (ms) | p90 (ms) | p95 (ms) | p99 (ms) |
|---|---|---|---|---|---|
| GET | /health |
4 | 13 | 19 | 900 |
| POST | /interact |
23 | 41 | 53 | 730 |
| GET | /recommend/feed/8 |
7 | 23 | 33 | 2,000 |
| Aggregated | 19 | 36 | 46 | 920 |
Key observations:
POST /interacthandles the highest load (39.1 RPS, 3Γ weight) with a p95 of 53ms β well within real-time UX thresholds.GET /recommend/feed/8achieves a p50 of 7ms for cached responses thanks to the 60-second TTL cache.GET /healthspikes at p99 (900ms) and max (3,014ms) due to occasional GIL contention under high concurrency β negligible for a health probe.- Zero failures across 10,420 total requests confirms production-grade stability.
Code Linting
flake8 src/
Contributing
- Fork the repository.
- Create a new branch:
git checkout -b feature/your-feature-name - Commit your changes using Conventional Commits.
- Push to the branch:
git push origin feature/your-feature-name - Open a Pull Request.
Ensure all code passes flake8 and pytest before submitting.
Commit Message Convention
| Prefix | Use for |
|---|---|
feat: |
New features |
fix: |
Bug fixes |
docs: |
Documentation changes |
refactor: |
Code restructuring without behavior change |
test: |
Adding or updating tests |
chore: |
Maintenance tasks (deps, CI, config) |
License
This project is licensed under the MIT License.
Copyright (c) 2026 SONIX RUSH
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Built with β€οΈ for the SONIX RUSH Application.