Recommendations
for any application.
NeuroMesh AI is a schema-agnostic recommendation SDK + REST API. Plug it into any data source — e-commerce, video, music, SaaS — and get personalised results in minutes.
What it does
X-Tenant-ID header. Persisted to PostgreSQL, restored on restart./metrics, structured JSON logs in production, PostgreSQL audit trail./recommend/explain.Quick example
from neuromesh import Recommender
items = [
{"id": "p1", "title": "Wireless Headphones", "category": "electronics"},
{"id": "p2", "title": "Gaming Mouse", "category": "electronics"},
{"id": "p3", "title": "Python Cookbook", "category": "books"},
{"id": "p4", "title": "Mechanical Keyboard", "category": "electronics"},
]
rec = Recommender(engine="tfidf")
rec.train(items)
for r in rec.recommend("p1", top_k=3):
print(f"[{r.rank}] {r.item_id} score={r.score:.3f}")
# [1] p2 score=0.812
# [2] p4 score=0.743
# [3] p3 score=0.021
What's new in v0.3.0
alembic upgrade head manages all schema changesNEUROMESH_VECTOR_STORE=pgvector stores embeddings in PostgreSQLNEUROMESH_ENGINE env var — configure default engine without code changesRecommender.load() now correctly restores incremental learner statepgvector accepted as valid NEUROMESH_VECTOR_STORE valueInstallation
Requires Python 3.11+. The base package includes TF-IDF, Trending engine, and the FastAPI server.
Base install
pip install neuromesh-ai
Optional extras
| Extra | What it adds | Command |
|---|---|---|
[embedding] | SentenceTransformers + FAISS vector search | pip install "neuromesh-ai[embedding]" |
[collaborative] | Implicit ALS collaborative filtering | pip install "neuromesh-ai[collaborative]" |
[qdrant] | Qdrant vector store client | pip install "neuromesh-ai[qdrant]" |
[chroma] | ChromaDB vector store | pip install "neuromesh-ai[chroma]" |
[pgvector] | pgvector PostgreSQL extension support | pip install "neuromesh-ai[pgvector]" |
[db] | SQLAlchemy async + asyncpg + Alembic | pip install "neuromesh-ai[db]" |
[cache] | Redis async client | pip install "neuromesh-ai[cache]" |
[prometheus] | Prometheus metrics endpoint | pip install "neuromesh-ai[prometheus]" |
[shopify] | Shopify product connector | pip install "neuromesh-ai[shopify]" |
[all] | All of the above except prometheus | pip install "neuromesh-ai[all]" |
[dev] | pytest, black, isort, mypy, pip-audit, build, twine | pip install "neuromesh-ai[dev]" |
[prometheus] is intentionally excluded from [all] — install it separately if you need Prometheus metrics.
Environment variables
All variables are prefixed NEUROMESH_. Copy to a .env file and load with python-dotenv or export directly.
| Variable | Default | Description |
|---|---|---|
NEUROMESH_ENV | development | Set to production to enforce CORS + JSON logs |
NEUROMESH_API_KEY | empty | X-API-Key secret. Empty = auth disabled |
NEUROMESH_ENGINE | tfidf | Default engine for new tenants |
NEUROMESH_HOST | 0.0.0.0 | FastAPI bind host |
NEUROMESH_PORT | 8000 | FastAPI bind port |
NEUROMESH_DATABASE_URL | empty | postgresql+asyncpg://user:pass@host/db |
NEUROMESH_REDIS_URL | redis://localhost:6379/0 | Redis connection URL |
NEUROMESH_VECTOR_STORE | faiss | faiss · qdrant · chroma · pgvector |
NEUROMESH_EMBEDDING_MODEL | all-MiniLM-L6-v2 | SentenceTransformers model name |
NEUROMESH_MODEL_PATH | empty | Path to auto-load/save joblib model |
NEUROMESH_CORS_ORIGINS | http://localhost:3000 | Required in production (comma-separated) |
NEUROMESH_RATE_LIMIT_PER_MINUTE | 60 | Per-IP per-tenant request limit |
NEUROMESH_MAX_TENANTS | 100 | Maximum simultaneous tenants |
NEUROMESH_LOG_LEVEL | INFO | DEBUG · INFO · WARNING · ERROR |
Verify the install
python -c "import neuromesh; print(neuromesh.__version__)"
# 0.3.0
Quick Start
Three paths: pure Python SDK, REST API, or Docker.
Option 1 — Python SDK
from neuromesh import Recommender
# 1. Define your items — any schema, only "id" is required
items = [
{"id": "p1", "title": "Wireless Headphones", "category": "electronics", "brand": "Sony"},
{"id": "p2", "title": "Gaming Mouse", "category": "electronics", "brand": "Logitech"},
{"id": "p3", "title": "Python Cookbook", "category": "books"},
{"id": "p4", "title": "Mechanical Keyboard", "category": "electronics", "brand": "Keychron"},
]
# User interaction data (optional — needed for collaborative / hybrid)
interactions = [
{"user_id": "alice", "item_id": "p1", "weight": 1.0},
{"user_id": "alice", "item_id": "p4", "weight": 0.8},
{"user_id": "bob", "item_id": "p2", "weight": 1.0},
]
# 2. Create and train
rec = Recommender(engine="tfidf") # or "embedding", "collaborative", "hybrid"
rec.train(items, interactions=interactions)
# 3. Item-based recommendations
print(rec.recommend("p1", top_k=3))
# 4. User-based recommendations (requires collaborative / hybrid engine)
rec2 = Recommender(engine="collaborative")
rec2.train(items, interactions=interactions)
print(rec2.recommend_for_user("alice", top_k=3))
# 5. Session-based (recency-weighted)
print(rec.recommend_for_session(["p3", "p1"], top_k=3))
# 6. Save and reload
rec.save("model.joblib") # writes model.joblib + model.joblib.sha256
rec_loaded = Recommender.load("model.joblib")
print(rec_loaded.recommend("p1", top_k=2))
Option 2 — REST API
Start the server
export NEUROMESH_API_KEY=dev-secret
uvicorn neuromesh.api:app --reload
Train
curl -X POST http://localhost:8000/v1/train \
-H "X-API-Key: dev-secret" \
-H "Content-Type: application/json" \
-d '{
"items": [
{"id":"p1","title":"Wireless Headphones","category":"electronics"},
{"id":"p2","title":"Gaming Mouse","category":"electronics"},
{"id":"p3","title":"Python Cookbook","category":"books"}
]
}'
Recommend
curl -X POST http://localhost:8000/v1/recommend \
-H "X-API-Key: dev-secret" \
-H "Content-Type: application/json" \
-d '{"item_id":"p1","top_k":5}'
{
"results": [
{"rank": 1, "item_id": "p2", "score": 0.812},
{"rank": 2, "item_id": "p3", "score": 0.021}
],
"engine": "tfidf",
"tenant_id": "default"
}
Option 3 — Docker Compose
git clone https://github.com/TheAmitChandra/NeuroMesh-AI.git
cd NeuroMesh-AI
cp .env.example .env # set NEUROMESH_API_KEY
docker compose -f docker/docker-compose.yml up -d
# API running at http://localhost:8000
Explore the API
Open http://localhost:8000/docs for interactive Swagger UI, or http://localhost:8000/redoc for ReDoc.
Recommendation Engines
NeuroMesh AI ships five engines. Choose one at construction time — or swap via NEUROMESH_ENGINE.
Engine selection guide
| Scenario | Recommended Engine |
|---|---|
| New catalogue, no user data | "tfidf" |
| Free-text product search or semantic matching | "embedding" |
| Personalisation with purchase/view history | "collaborative" |
| Homepage / category trending feed | "trending" |
| Production with mixed signals | "hybrid" |
Common interface
All five engines implement the same BaseEngine interface:
engine.fit(items, corpus, popularity_scores, freshness_scores, interactions)
engine.recommend(item_id, top_k, exclude_ids) # → list[RecommendationResult]
engine.similar(item_id, top_k, exclude_ids)
engine.recommend_for_user(user_id, top_k, exclude_ids) # raises NotImplementedError if unsupported
engine.engine_name # str
engine.is_fitted # bool
Incremental learning
| Engine | add_item() | add_interaction() |
|---|---|---|
| tfidf | Buffered — visible after next train() | Buffered |
| embedding | ✅ Immediate (HNSW insert) | Buffered |
| collaborative | Buffered | ✅ Immediate (IncrementalLearner) |
| trending | Buffered | ✅ Immediate (score update) |
| hybrid | Delegates to sub-engines | Delegates to sub-engines |
Per-engine example
from neuromesh import Recommender
# Semantic embedding (requires pip install "neuromesh-ai[embedding]")
rec = Recommender(engine="embedding")
rec.train(items)
results = rec.recommend("p1", top_k=5)
# Collaborative (requires pip install "neuromesh-ai[collaborative]")
rec = Recommender(engine="collaborative")
rec.train(items, interactions=user_interactions)
results = rec.recommend_for_user("user-42", top_k=5)
# Trending
rec = Recommender(engine="trending")
rec.train(items)
results = rec.recommend("p1", top_k=5) # ranks by popularity × freshness
# Hybrid (requires pip install "neuromesh-ai[all]")
rec = Recommender(engine="hybrid")
rec.train(items, interactions=user_interactions)
results = rec.recommend("p1", top_k=5)
API Reference
Base URL: http://localhost:8000 (dev) · https://your-host (prod)
Version prefix: /v1 | OpenAPI UI: /docs · /redoc
Set X-API-Key: <your-key> on every request when NEUROMESH_API_KEY is set. Health check is always public.
Pass X-Tenant-ID: shop-a to scope all operations to a tenant. Omit for the default tenant.
Endpoints
{"status":"ok","version":"0.3.0","engine":"tfidf","fitted":true}
Train (or re-train) the recommendation engine on your item catalogue.
{
"items": [
{"id":"item-1","title":"Wireless Headphones","category":"electronics"}
],
"interactions": [
{"user_id":"alice","item_id":"item-1","weight":1.0}
]
}
{"items_trained":42,"engine":"tfidf"}
{"item_id":"item-1","top_k":10,"exclude_ids":[],"variant":"default"}
{"results":[{"rank":1,"item_id":"item-2","score":0.94}],"engine":"tfidf","tenant_id":"default"}
Personalised recommendations for a user. Falls back to trending for unknown users (cold-start). Returns HTTP 501 if the active engine does not support user recommendations.
{"user_id":"alice","top_k":10,"exclude_ids":[]}
Recency-weighted recommendations from a browsing session. The last item in session_item_ids gets weight 1.0; each earlier item is weighted × 0.8. Order is significant — the cache key preserves it.
{"session_item_ids":["item-3","item-7","item-1"],"top_k":10}
{"top_k":10,"category":"electronics","exclude_ids":[]}
{
"item_id":"item-1","engine":"tfidf",
"explanation_text":"Items recommended because they share keywords: electronics, gaming",
"results":[{"rank":1,"item_id":"item-2","score":0.94,"explanation":"High TF-IDF similarity (0.94)"}]
}
{"item_id":"item-1","top_k":5,"exclude_ids":[]}
Only EmbeddingEngine supports true fast-path incremental addition. For TF-IDF, items are buffered and become searchable only after a full POST /v1/train.
{"item":{"id":"item-999","title":"New Product","category":"electronics"}}
{"user_id":"alice","item_id":"item-1","event_type":"purchase","score":1.0}
{"recommendation_id":"rec-abc","item_id":"item-2","feedback_type":"click","score":1.0}
Writes NEUROMESH_MODEL_PATH + a .sha256 integrity sidecar.
{"status":"ok","path":"/var/neuromesh/model.joblib","items_saved":42}
{"tenants":[{"tenant_id":"default","engine":"tfidf","fitted":true,"item_count":42}],"total":1}
{"tenant_id":"shop-a","engine":"hybrid"}
Marks the tenant inactive in PostgreSQL and removes it from memory. The default tenant cannot be deleted.
Rolling recommendation quality metrics. Requires PostgreSQL (NEUROMESH_DATABASE_URL).
Requires pip install "neuromesh-ai[prometheus]". Exposes standard request counters, latency histograms, and engine health.
Error format
{"error":"Item 'item-99' not found in the catalogue.","code":"item_not_found","details":{}}
| Status | Meaning |
|---|---|
400 | Bad request — invalid input |
401 | Missing or invalid API key |
404 | Item / resource not found |
422 | Request body validation failed |
429 | Rate limit exceeded |
501 | Feature not supported by active engine |
503 | Engine not yet fitted — call POST /v1/train first |
Multi-Tenancy
Run one NeuroMesh deployment for multiple clients — each with a fully isolated recommendation engine, interaction history, and rate-limit bucket.
How it works
X-Tenant-IDheader selects the tenant (default:"default")- Each tenant owns its own
Recommenderinstance — data never bleeds across tenants - Tenant list is persisted to PostgreSQL and restored automatically on server restart
- The
defaulttenant always exists and cannot be deleted
Create a tenant
curl -X POST http://localhost:8000/v1/tenants \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{"tenant_id":"shop-a","engine":"hybrid"}'
Tenant-scoped training and recommendations
# Train shop-a
curl -X POST http://localhost:8000/v1/train \
-H "X-API-Key: your-key" -H "X-Tenant-ID: shop-a" \
-d '{"items":[{"id":"p1","title":"Widget"}]}'
# Get recommendations for shop-a — completely isolated from other tenants
curl -X POST http://localhost:8000/v1/recommend \
-H "X-API-Key: your-key" -H "X-Tenant-ID: shop-a" \
-d '{"item_id":"p1","top_k":5}'
Default engine for new tenants
NEUROMESH_ENGINE=hybrid # tfidf | embedding | collaborative | trending | hybrid
Tenant cap
NEUROMESH_MAX_TENANTS=100
When the cap is reached, auto-creation returns HTTP 429. Register tenants explicitly via POST /v1/tenants first.
A/B testing
curl -X POST http://localhost:8000/v1/ab \
-H "X-API-Key: your-key" \
-d '{
"experiment_id":"engine-test",
"variants":[
{"name":"control","engine":"tfidf","weight":0.5},
{"name":"treatment","engine":"hybrid","weight":0.5}
]
}'
Tenant model state is in-memory per process. With gunicorn -w 4, each worker has its own models. Use sticky sessions, or set NEUROMESH_MODEL_PATH to a shared volume and call POST /v1/model/save after training.
Model Persistence
Save a trained model to disk and reload it across process restarts, deployments, or server migrations — without re-training.
Save and load (SDK)
rec = Recommender(engine="tfidf")
rec.train(items)
# Writes: model.joblib + model.joblib.sha256
rec.save("model.joblib")
# Loads and verifies the SHA-256 sidecar before deserialising
rec2 = Recommender.load("model.joblib")
results = rec2.recommend("item-1", top_k=5)
| File | Contents |
|---|---|
model.joblib | Serialised engine state (joblib / pickle format) |
model.joblib.sha256 | SHA-256 hex digest of the joblib file |
If .sha256 does not exist alongside the joblib file, load() skips verification and proceeds normally — backward compatible with models saved before v0.3.0.
Auto-load at startup
Set NEUROMESH_MODEL_PATH so the API server loads the model on startup and saves after every successful training:
NEUROMESH_MODEL_PATH=/var/neuromesh/model.joblib
Save via API
curl -X POST http://localhost:8000/v1/model/save -H "X-API-Key: your-key"
# {"status":"ok","path":"/var/neuromesh/model.joblib","items_saved":42}
Security
A maliciously crafted .joblib can execute arbitrary Python on load. Never load a model from an untrusted source. Always verify the .sha256 sidecar is present. Store model files on access-controlled volumes.
Integrations
Only id is required on items — bring your own schema. Any data source that can produce a list of dicts works.
Shopify
from neuromesh.integrations.shopify import ShopifyConnector
from neuromesh import Recommender
connector = ShopifyConnector(
shop_url="https://your-store.myshopify.com",
access_token="shpat_xxxx",
)
items = connector.fetch_products()
rec = Recommender(engine="hybrid")
rec.train(items)
Odoo ERP
from neuromesh.integrations.odoo import OdooConnector
from neuromesh import Recommender
connector = OdooConnector(
url="https://your-odoo.com",
db="your_db",
username="admin",
api_key="your_odoo_api_key",
)
items = connector.fetch_products()
interactions = connector.fetch_orders() # order lines → interactions
rec = Recommender(engine="collaborative")
rec.train(items, interactions=interactions)
WooCommerce / Generic REST
import httpx
from neuromesh import Recommender
products = httpx.get(
"https://myshop.com/wp-json/wc/v3/products",
auth=("ck_xxx", "cs_xxx"),
).json()
rec = Recommender(engine="tfidf")
rec.train(products) # "id" field used automatically
CSV / DataFrame
import pandas as pd
from neuromesh import Recommender
df = pd.read_csv("products.csv")
items = df.to_dict(orient="records")
rec = Recommender(engine="tfidf")
rec.train(items)
Vector store backends
| Backend | Extra | Best for |
|---|---|---|
| FAISS (default) | [embedding] | Local dev, single-node production |
| Qdrant | [qdrant] | Scalable, horizontally shardable |
| ChromaDB | [chroma] | Developer-friendly, easy local setup |
| pgvector | [pgvector] | Already-running PostgreSQL clusters |
NEUROMESH_VECTOR_STORE=pgvector # faiss | qdrant | chroma | pgvector
# pgvector requires:
NEUROMESH_DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/neuromesh
Redis cache
The recommendation cache degrades gracefully to no-op when Redis is unavailable — no hard crash.
NEUROMESH_REDIS_URL=redis://localhost:6379/0
# TLS:
NEUROMESH_REDIS_URL=rediss://user:password@myredis.example.com:6380/0
Deployment
Database migrations
pip install "neuromesh-ai[db]"
export NEUROMESH_DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/neuromesh
python scripts/setup_db.py # runs alembic upgrade head
Docker Compose
git clone https://github.com/TheAmitChandra/NeuroMesh-AI.git && cd NeuroMesh-AI
cp .env.example .env
docker compose -f docker/docker-compose.yml up -d
docker compose exec neuromesh-api python scripts/setup_db.py
services:
neuromesh:
image: ghcr.io/theamitchandra/neuromesh-ai:latest
ports: ["8000:8000"]
environment:
NEUROMESH_ENV: production
NEUROMESH_API_KEY: change-me
NEUROMESH_ENGINE: tfidf
NEUROMESH_REDIS_URL: redis://redis:6379/0
NEUROMESH_DATABASE_URL: postgresql+asyncpg://postgres:postgres@db:5432/neuromesh
NEUROMESH_MODEL_PATH: /var/neuromesh/model.joblib
NEUROMESH_CORS_ORIGINS: https://your-frontend.com
volumes: [neuromesh_models:/var/neuromesh]
depends_on: [redis, db]
redis:
image: redis:7-alpine
db:
image: pgvector/pgvector:pg16
environment: {POSTGRES_DB: neuromesh, POSTGRES_USER: postgres, POSTGRES_PASSWORD: postgres}
volumes: [pgdata:/var/lib/postgresql/data]
volumes: {neuromesh_models: {}, pgdata: {}}
Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata: {name: neuromesh-api}
spec:
replicas: 1 # see multi-worker note — use sticky sessions for >1
selector: {matchLabels: {app: neuromesh-api}}
template:
metadata: {labels: {app: neuromesh-api}}
spec:
containers:
- name: api
image: ghcr.io/theamitchandra/neuromesh-ai:latest
ports: [{containerPort: 8000}]
env:
- name: NEUROMESH_API_KEY
valueFrom: {secretKeyRef: {name: neuromesh-secrets, key: api-key}}
- name: NEUROMESH_MODEL_PATH
value: /var/neuromesh/model.joblib
volumeMounts: [{name: model-storage, mountPath: /var/neuromesh}]
livenessProbe:
httpGet: {path: /v1/health, port: 8000}
initialDelaySeconds: 15
periodSeconds: 30
volumes:
- name: model-storage
persistentVolumeClaim: {claimName: neuromesh-model-pvc}
GitHub Actions workflows
| Workflow | File | Trigger |
|---|---|---|
| Lint + Tests | ci.yml | Push / PR to main |
| Docker Build → GHCR | docker.yml | Push to main or version tags |
| Publish to PyPI | publish.yml | GitHub Release published |
| Docs Site | docs.yml | Push touching website/** |
Production checklist
- Set
NEUROMESH_API_KEYto a cryptographically random string - Set
NEUROMESH_ENV=production— enforces CORS, enables JSON logs - Set
NEUROMESH_CORS_ORIGINSto your frontend domain(s) - Use a managed PostgreSQL instance (AWS RDS, GCP Cloud SQL, etc.)
- Use a managed Redis instance (ElastiCache, Redis Cloud, etc.)
- Set
NEUROMESH_MODEL_PATHto a persistent volume - Run
alembic upgrade headbefore first start and after upgrades - Enable TLS — terminate at nginx, Caddy, or your load balancer
- Monitor
GET /v1/healthwith your uptime tool - For multi-worker: use sticky sessions or set
replicas: 1
