UNPKG

@athenox/talos

Version:

Talos: a backend you describe instead of write. Declare a schema, write the rules in plain language, map URLs to sentences; a small built-in model turns them into query plans.

50 lines (37 loc) • 2 kB
# Search and recommendations All three rank the rows the plan chose, so the route's conditions, roles and ownership still apply. They use Talos's own text embedder (shipped with the model; French and English) for meaning, next to the words. ## Search ```ts 'GET /api/recipes': { say: 'show the recipes', shape: p => ({ search: p.q }) } // over `searchable` 'GET /api/articles': { say: 'show the articles', shape: p => ({ find: { q: p.q, fields: { title: 3, excerpt: 2, body: 1 }, html: true, limit: 20, suggest: 'title' } }) } ``` `find` weighs fields (BM25), matches prefixes and one-letter typos, ignores stop words and HTML, and falls back on meaning when no word matches. `suggest: 'title'` turns it into autocompletion on the query's last word. `find(rows, options)` is also exported, for rows you already have. ## Similar rows ```ts 'GET /api/recipes/:id/similar': { say: 'show the recipes', pin: false, limit: 4, shape: p => ({ similar: { to: { id: Number(p.id) }, text: ['title', 'summary', 'ingredients'] } }) } ``` `to` is a row (`{ id }`, left out of the result) or a text. Words (TF-IDF) and meaning, mixed 70/30. ## Recommendations ```ts 'GET /api/for-you': { say: 'show the recipes', guard: member, limit: 4, shape: (_, me) => ({ recommend: { user: me.id, interactions: { table: 'likes', user: 'user_id', item: 'recipe_id' }, // one row per (user, item) text: ['title', 'summary'], date: 'created_at', halfLife: 30, weights: { content: 1, together: 1, popular: 0.3, recent: 0.3 }, } }) } ``` Each candidate is scored by how close it is to what the reader already liked (`content`), what readers who liked the same things liked (`together`), popularity and recency. Items already seen are left out (`keepSeen: true` to keep them); a visitor (`user: null`) gets popular and recent. ## Meaning, directly `embedText(text)`, `cosine(a, b)`, `classify(text, { sport: 'match, stade', culture: 'concert' })`, and the schema's `infer` (a column filled by meaning).