Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Semantic Intent Engine

Moteur de recherche sémantique pour un catalogue e-commerce. Le client décrit ce qu'il veut en langage naturel — le moteur comprend l'intention et remonte les bons produits.

"un truc pour mon frigo"                    → Framed Magnet 4x4
"cadeau pour ma mère"                       → Framed Canvas 8x10
"décorer mon salon avec du design moderne"  → Canvas 16x20, Metal Panel 11x14
"album photo de notre voyage au Japon"      → Photobook Hardcover 8.5x11

FR et EN indifféremment, même modèle. 100 % local, zéro API externe, zéro coût.


Comment ça marche

Le problème

Une searchbar classique matche des mots-clés. Le client doit connaître le vocabulaire du catalogue (canvas_11x14, framed_magnet_4x4). En réalité, il pense en intention : "un truc déco pour mon salon", "quelque chose de carré pour Instagram".

La solution : un pipeline RAG en 4 étapes

Query "un truc pour mon frigo"
  │
  ▼
1. EMBEDDING (~30 ms)
   La phrase → 768 nombres (coordonnée sémantique).
   Modèle multilingue : "frigo" et "fridge" atterrissent au même endroit.
  │
  ▼
2. VECTOR SEARCH (~5 ms)
   Trouver les 30 produits dont les coordonnées sont les plus proches.
   SQLite + sqlite-vec, distance cosine.
  │
  ▼
3. INTENT BOOST + RE-RANKING (~500 ms)
   Règles déterministes FR/EN ("frigo" → boost magnets, malus wall art).
   Cross-encoder relit chaque paire (query, produit) ensemble pour affiner.
  │
  ▼
4. GENERATION optionnelle (~1 s)
   Un LLM local rédige 3-4 phrases expliquant pourquoi ces produits matchent.

Latence totale : ~500 ms (sans génération). Exploitable comme searchbar.


Architecture

frontend/     Vite + React + Tailwind — landing page, searchbar, modale de résultats
backend/      FastAPI — pipeline RAG complet
scripts/      Enrichissement catalogue (LLM) + indexation (embedding → SQLite)
data/         Catalogue brut (52 produits) + index vectoriel
tests/        Suite d'acceptation pytest (12 queries × 2 niveaux de strictness)
docs/         Design doc, flow pipeline, présentation
┌─────────────────┐    POST /search    ┌──────────────────────────────────┐
│    Frontend      │ ────────────────> │          Backend RAG             │
│  localhost:3000  │                   │        localhost:8000            │
│                  │    JSON response  │                                  │
│  SearchBarHero   │ <──────────────── │  embed → search → boost →       │
│  Modal + cards   │                   │  rerank → (LLM generation)      │
└─────────────────┘                    └──────────────────────────────────┘
                                                │              │
                                         ┌──────┘              └──────┐
                                         ▼                            ▼
                                   ┌───────────┐              ┌────────────┐
                                   │ sqlite-vec│              │   Ollama   │
                                   │catalog.db │              │ qwen2.5:7b │
                                   └───────────┘              └────────────┘

Stack

Composant Technologie Rôle
Embedding intfloat/multilingual-e5-base (768 dim) Texte → vecteur sémantique, bilingue FR/EN
Vector store sqlite-vec (SQLite extension) Recherche par proximité cosine
Re-ranker BAAI/bge-reranker-v2-m3 Affine le classement en lisant query + produit ensemble
Intent boost Règles déterministes FR/EN Détecte "frigo", "salon", "cadeau"… → boost/malus sur les specs
LLM qwen2.5:7b via Ollama (local) Enrichissement offline + explication online (toggle)
Backend FastAPI + Python Pipeline + API REST
Frontend Vite + React 19 + Tailwind 4 Landing page + modale immersive

Quickstart

Prérequis

  • Python 3.11+ (uv recommandé)
  • Node.js 18+ + pnpm
  • Ollama

1. Backend

# Venv Python
uv venv --python 3.11
source .venv/bin/activate
uv pip install -r backend/requirements.txt

# LLM local
brew install ollama
brew services start ollama
ollama pull qwen2.5:7b

# Enrichir + indexer le catalogue (~18 min la première fois, idempotent ensuite)
python scripts/enrich_catalog.py
python scripts/index_catalog.py

# Lancer
uvicorn backend.main:app --host 0.0.0.0 --port 8000

2. Frontend

cd frontend
pnpm install
pnpm dev    # → http://localhost:3000

3. Tester

# Health check
curl http://localhost:8000/health

# Recherche
curl -X POST http://localhost:8000/search \
  -H "Content-Type: application/json" \
  -d '{"query": "un truc pour mon frigo", "top_k": 6}'

# Tests d'acceptation
pytest tests/ -v

Le point clé : l'enrichissement des fiches

Les fiches produit brutes sont techniques (canvas_11x14, DPI 300, 11 inches). Un modèle d'embedding n'en tirera rien de sémantique.

Le script enrich_catalog.py passe chaque produit dans un prompt strict à qwen qui génère :

  • ideal_for : usages client ("décorer un salon", "cadeau pour un mariage"…)
  • semantic_keywords : mots-clés FR/EN ("salon", "living room", "cadeau", "gift"…)
  • context_phrases : phrases client complètes en FR et EN
  • occasions, rooms_or_locations, photo_subjects, style_tags

Le prompt est contrôlé par archetype (un magnet ≠ un canvas) et par tier de prix (un print à 0,79 $ ne peut pas être tagué "premium/luxury"). Ça évite les hallucinations et donne au re-ranker du signal à discriminer.


API

POST /search

{
  "query": "un truc pour mon frigo",
  "top_k": 6,
  "use_llm": false,
  "use_llm_expansion": false
}
Paramètre Défaut Description
query requis Texte libre (FR ou EN)
top_k 6 Nombre de résultats
use_llm false Active l'explication en langage naturel (+~1 s)
use_llm_expansion false Décompose la query en 3 facettes pour queries complexes (+~1 s)

GET /health

{
  "status": "ok",
  "products_indexed": 52,
  "ollama": { "reachable": true, "llm_model_available": true },
  "llm_model": "qwen2.5:7b"
}

Docs


Licence

Usage interne.

About

Recherche sémantique par intention

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages