PyPI GitHub
esc
Start typing to search documentation
NeuroMesh AI
v0.3.0 — Now on PyPI

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.

$ pip install neuromesh-ai
GitHub
5
Recommendation Engines
19
REST Endpoints
620
Tests Passing
83%
Code Coverage

What it does

Five Engines
TF-IDF, Semantic Embeddings, Collaborative Filtering, Trending, and Hybrid — swap with one parameter.
🏢
Multi-Tenancy
Isolated engine per tenant via X-Tenant-ID header. Persisted to PostgreSQL, restored on restart.
🧠
Session Recs
Recency-weighted blend of a multi-item browsing session. Last-viewed item gets highest weight.
🔒
Model Integrity
SHA-256 sidecar written on every save and verified on load. Detects corruption and tampering.
📊
Observability
Prometheus /metrics, structured JSON logs in production, PostgreSQL audit trail.
🐳
Docker-Ready
One command brings up API + PostgreSQL + Redis. Kubernetes YAML included.
💡
Explainability
Human-readable reason strings alongside every recommendation via /recommend/explain.
🔌
Integrations
Built-in connectors for Shopify and Odoo. Bring your own for WooCommerce, WordPress, or CSV.

Quick example

Python
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

NEWAlembic database migrations — alembic upgrade head manages all schema changes
NEWPersistent multi-tenancy — tenant state survives server restarts via PostgreSQL
NEWpgvector support — NEUROMESH_VECTOR_STORE=pgvector stores embeddings in PostgreSQL
NEWSession recommendations — recency-weighted multi-item browsing context
SECURITYSHA-256 integrity sidecar on every model save — tampering detected on load
SECURITYError messages sanitized — internal exceptions never leak to API responses
IMPROVEDNEUROMESH_ENGINE env var — configure default engine without code changes
FIXEDBUG-1 (critical): Recommender.load() now correctly restores incremental learner state
FIXEDBUG-2 (high): pgvector accepted as valid NEUROMESH_VECTOR_STORE value
FIXEDBUG-3 (medium): Session cache key preserves item order for correct recency weighting

Installation

Requires Python 3.11+. The base package includes TF-IDF, Trending engine, and the FastAPI server.

Base install

bash
pip install neuromesh-ai

Optional extras

ExtraWhat it addsCommand
[embedding]SentenceTransformers + FAISS vector searchpip install "neuromesh-ai[embedding]"
[collaborative]Implicit ALS collaborative filteringpip install "neuromesh-ai[collaborative]"
[qdrant]Qdrant vector store clientpip install "neuromesh-ai[qdrant]"
[chroma]ChromaDB vector storepip install "neuromesh-ai[chroma]"
[pgvector]pgvector PostgreSQL extension supportpip install "neuromesh-ai[pgvector]"
[db]SQLAlchemy async + asyncpg + Alembicpip install "neuromesh-ai[db]"
[cache]Redis async clientpip install "neuromesh-ai[cache]"
[prometheus]Prometheus metrics endpointpip install "neuromesh-ai[prometheus]"
[shopify]Shopify product connectorpip install "neuromesh-ai[shopify]"
[all]All of the above except prometheuspip install "neuromesh-ai[all]"
[dev]pytest, black, isort, mypy, pip-audit, build, twinepip install "neuromesh-ai[dev]"
Note

[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.

VariableDefaultDescription
NEUROMESH_ENVdevelopmentSet to production to enforce CORS + JSON logs
NEUROMESH_API_KEYemptyX-API-Key secret. Empty = auth disabled
NEUROMESH_ENGINEtfidfDefault engine for new tenants
NEUROMESH_HOST0.0.0.0FastAPI bind host
NEUROMESH_PORT8000FastAPI bind port
NEUROMESH_DATABASE_URLemptypostgresql+asyncpg://user:pass@host/db
NEUROMESH_REDIS_URLredis://localhost:6379/0Redis connection URL
NEUROMESH_VECTOR_STOREfaissfaiss · qdrant · chroma · pgvector
NEUROMESH_EMBEDDING_MODELall-MiniLM-L6-v2SentenceTransformers model name
NEUROMESH_MODEL_PATHemptyPath to auto-load/save joblib model
NEUROMESH_CORS_ORIGINShttp://localhost:3000Required in production (comma-separated)
NEUROMESH_RATE_LIMIT_PER_MINUTE60Per-IP per-tenant request limit
NEUROMESH_MAX_TENANTS100Maximum simultaneous tenants
NEUROMESH_LOG_LEVELINFODEBUG · INFO · WARNING · ERROR

Verify the install

bash
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

Python
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

bash
export NEUROMESH_API_KEY=dev-secret
uvicorn neuromesh.api:app --reload

Train

bash
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

bash
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}'
json — Response
{
  "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

bash
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.

"tfidf" TFIDFEngine
Content-based similarity using TF-IDF vectors over item text fields. Fast, zero GPU required, great default for most catalogues.
Defaultscikit-learnNo extras
"embedding" EmbeddingEngine
Semantic similarity via SentenceTransformers + FAISS ANN. Understands meaning, handles free-text queries. Supports true incremental item addition.
pip install [embedding]GPU optional
"collaborative" CollaborativeEngine
ALS matrix factorisation (implicit library) over user–item interaction history. Best for personalisation when you have interaction data.
pip install [collaborative]Needs interactions
"trending" TrendingEngine
Ranks items by popularity × freshness score. Perfect for homepage feeds and category pages where recency matters.
No extrasIncluded in base
"hybrid" HybridEngine
Weighted blend of TF-IDF + Embedding + Collaborative + Trending signals. Highest accuracy. Falls back gracefully when sub-engines lack data.
All extras requiredRecommended for production

Engine selection guide

ScenarioRecommended 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:

Python
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

Engineadd_item()add_interaction()
tfidfBuffered — visible after next train()Buffered
embedding✅ Immediate (HNSW insert)Buffered
collaborativeBuffered✅ Immediate (IncrementalLearner)
trendingBuffered✅ Immediate (score update)
hybridDelegates to sub-enginesDelegates to sub-engines

Per-engine example

Python
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

Authentication

Set X-API-Key: <your-key> on every request when NEUROMESH_API_KEY is set. Health check is always public.

Multi-tenancy

Pass X-Tenant-ID: shop-a to scope all operations to a tenant. Omit for the default tenant.

Endpoints

GET/v1/healthHealth check — no auth required
json — Response 200
{"status":"ok","version":"0.3.0","engine":"tfidf","fitted":true}
POST/v1/trainTrain the engine · 10/min

Train (or re-train) the recommendation engine on your item catalogue.

json — Request
{
  "items": [
    {"id":"item-1","title":"Wireless Headphones","category":"electronics"}
  ],
  "interactions": [
    {"user_id":"alice","item_id":"item-1","weight":1.0}
  ]
}
json — Response 200
{"items_trained":42,"engine":"tfidf"}
POST/v1/recommendItem-based · 60/min
json — Request
{"item_id":"item-1","top_k":10,"exclude_ids":[],"variant":"default"}
json — Response 200
{"results":[{"rank":1,"item_id":"item-2","score":0.94}],"engine":"tfidf","tenant_id":"default"}
POST/v1/recommend/userPersonalised · 60/min

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.

json — Request
{"user_id":"alice","top_k":10,"exclude_ids":[]}
POST/v1/recommend/sessionSession context · 60/min

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.

json — Request
{"session_item_ids":["item-3","item-7","item-1"],"top_k":10}
POST/v1/recommend/trendingTrending feed · 60/min
json — Request
{"top_k":10,"category":"electronics","exclude_ids":[]}
POST/v1/recommend/explainWith explanations · 30/min
json — Response 200
{
  "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)"}]
}
POST/v1/similarSimilar items · 60/min
json — Request
{"item_id":"item-1","top_k":5,"exclude_ids":[]}
POST/v1/add-itemIncremental item · 120/min
Note

Only EmbeddingEngine supports true fast-path incremental addition. For TF-IDF, items are buffered and become searchable only after a full POST /v1/train.

json — Request
{"item":{"id":"item-999","title":"New Product","category":"electronics"}}
POST/v1/add-interactionRecord event · 300/min
json — Request
{"user_id":"alice","item_id":"item-1","event_type":"purchase","score":1.0}
POST/v1/feedbackRec feedback · 300/min
json — Request
{"recommendation_id":"rec-abc","item_id":"item-2","feedback_type":"click","score":1.0}
POST/v1/model/savePersist model · 5/min

Writes NEUROMESH_MODEL_PATH + a .sha256 integrity sidecar.

json — Response 200
{"status":"ok","path":"/var/neuromesh/model.joblib","items_saved":42}
GET/v1/tenantsList tenants · 30/min
json — Response 200
{"tenants":[{"tenant_id":"default","engine":"tfidf","fitted":true,"item_count":42}],"total":1}
POST/v1/tenantsCreate tenant · 20/min
json — Request
{"tenant_id":"shop-a","engine":"hybrid"}
DEL/v1/tenants/{tenant_id}Remove tenant · 10/min

Marks the tenant inactive in PostgreSQL and removes it from memory. The default tenant cannot be deleted.

GET/v1/metrics/qualityQuality metrics — no auth

Rolling recommendation quality metrics. Requires PostgreSQL (NEUROMESH_DATABASE_URL).

GET/metricsPrometheus metrics

Requires pip install "neuromesh-ai[prometheus]". Exposes standard request counters, latency histograms, and engine health.

Error format

json
{"error":"Item 'item-99' not found in the catalogue.","code":"item_not_found","details":{}}
StatusMeaning
400Bad request — invalid input
401Missing or invalid API key
404Item / resource not found
422Request body validation failed
429Rate limit exceeded
501Feature not supported by active engine
503Engine 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

Create a tenant

bash
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

bash
# 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

bash — .env
NEUROMESH_ENGINE=hybrid   # tfidf | embedding | collaborative | trending | hybrid

Tenant cap

bash — .env
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

bash
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}
    ]
  }'
Multi-worker warning

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)

Python
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)
FileContents
model.joblibSerialised engine state (joblib / pickle format)
model.joblib.sha256SHA-256 hex digest of the joblib file
Legacy models

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:

bash — .env
NEUROMESH_MODEL_PATH=/var/neuromesh/model.joblib

Save via API

bash
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

Model files are pickle format

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

Python
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

Python
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

Python
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

Python
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

BackendExtraBest 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
bash — .env
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.

bash — .env
NEUROMESH_REDIS_URL=redis://localhost:6379/0
# TLS:
NEUROMESH_REDIS_URL=rediss://user:password@myredis.example.com:6380/0

Deployment

Database migrations

bash
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

bash
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
yaml — docker-compose.yml (minimal)
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

yaml
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

WorkflowFileTrigger
Lint + Testsci.ymlPush / PR to main
Docker Build → GHCRdocker.ymlPush to main or version tags
Publish to PyPIpublish.ymlGitHub Release published
Docs Sitedocs.ymlPush touching website/**

Production checklist