Stack Python - Implémentation
Date : 2026-01-24
Statut : ✅ Infrastructure Complétée - Production Ready
Dernière mise à jour : 2026-01-24
🚀 Optimisations Récentes (2026-01-24)
- ✅ Build Docker optimisé : PaddleOCR optionnel (build rapide ~2-3 minutes avec EasyOCR par défaut)
- ✅ Permissions corrigées : Installation dans
/usr/localpour utilisateur non-root - ✅ Structure Python :
app/config/__init__.pypour éviter conflit de noms - ✅ Compatibilité : sentence-transformers mis à jour pour compatibilité avec huggingface_hub
🎯 Objectif
Intégrer une stack Python pour des cas d'usage avancés (ML, embeddings, analytics) qui bénéficient de l'écosystème Python, tout en conservant l'architecture NestJS/BullMQ existante.
✅ Ce qui a été fait
1. Service Python FastAPI
Structure créée
- ✅ Service FastAPI :
python-service/avec structure modulaire - ✅ Embeddings Service : Service pour générer des embeddings avec sentence-transformers
- ✅ Health checks : Endpoints de santé et readiness
- ✅ Configuration : Settings avec Pydantic
- ✅ Dockerfile : Image Docker optimisée
Endpoints disponibles
GET /health- Health checkGET /health/ready- Readiness checkPOST /api/embeddings/text- Générer un embedding pour un textePOST /api/embeddings/texts- Générer des embeddings pour plusieurs textes (batch)
2. Worker NestJS (worker-ml)
Modules créés
- ✅ WorkerMlModule : Module principal du worker ML
- ✅ PythonMlService : Service HTTP pour communiquer avec le service Python
- ✅ MlEmbedTextProcessor : Processor pour les jobs
ml:embed_text - ✅ MlEmbedTextsProcessor : Processor pour les jobs
ml:embed_texts(batch)
Intégration
- ✅ Queue PYTHON_ML : Nouvelle queue BullMQ pour les jobs Python
- ✅ WorkersQueueService : Méthodes
enqueueMlEmbedText()etenqueueMlEmbedTexts() - ✅ Types et schémas : Payloads
MlEmbedTextPayloadetMlEmbedTextsPayloadavec validation Zod - ✅ WorkerModule : Intégration du
WorkerMlModuledans le worker principal
3. Infrastructure Docker
Services ajoutés
- ✅ python-ml-service : Service Python FastAPI
- ✅ qdrant : Base de données vectorielle (prête pour utilisation future)
Configuration
- ✅ Variables d'environnement pour le service Python
- ✅ Dépendances entre services (worker → python-ml-service)
- ✅ Volumes persistants pour Qdrant
📊 Architecture
┌─────────────┐
│ NestJS │
│ Backend │
└──────┬──────┘
│ BullMQ Jobs (ml:embed_text, ml:embed_texts)
↓
┌─────────────────┐
│ Worker NestJS │
│ (worker-ml) │
└──────┬──────────┘
│ HTTP REST
↓
┌─────────────────┐
│ Python Service │
│ (FastAPI) │
│ │
│ - Embeddings │
│ - ML │
└─────────────────┘
│
↓
┌─────────────────┐
│ Qdrant │
│ (Vector DB) │
└─────────────────┘
🚀 Utilisation
Enqueueer un job d'embedding
import { WorkersQueueService } from "@/workers/workers-queue.service";
// Embedding d'un seul texte
const jobId = await workersQueueService.enqueueMlEmbedText({
v: 1,
orgId: "org-uuid",
userId: "user-uuid",
entityId: "entity-uuid",
text: "Ceci est un texte à embedder",
model: "sentence-transformers/all-MiniLM-L6-v2", // Optionnel
requestId: "request-uuid", // Pour tracking via JobRunsService
});
// Embedding de plusieurs textes (batch)
const jobId = await workersQueueService.enqueueMlEmbedTexts({
v: 1,
orgId: "org-uuid",
userId: "user-uuid",
entityId: "entity-uuid",
texts: ["Texte 1", "Texte 2", "Texte 3"],
model: "sentence-transformers/all-MiniLM-L6-v2", // Optionnel
requestId: "request-uuid",
});
Polling du statut
Le job est tracké via JobRunsService comme tous les autres jobs :
import { useJobRun } from "@/client/job-runs/useJobRuns";
const { data: jobRun, isLoading } = useJobRun(requestId);
// jobRun.result contient { embedding, model, dimension }
📋 Variables d'environnement
Backend (NestJS)
PYTHON_ML_SERVICE_URL=http://python-ml-service:8000
Python Service
DEBUG=false
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
EMBEDDING_DEVICE=cpu # ou cuda si GPU disponible
QDRANT_HOST=qdrant
QDRANT_PORT=6333
QDRANT_GRPC_PORT=6334
✅ Phase 2 : Intégration Qdrant (Complétée)
Services créés
- ✅ QdrantService : Service Python pour gérer Qdrant
- ✅ Endpoints Qdrant : CRUD complet pour les collections et points
- ✅ Processors NestJS : 4 processors pour les opérations Qdrant
- ✅ Types et schémas : Payloads complets avec validation Zod
Opérations disponibles
- ✅
ml:qdrant:create_collection- Créer une collection - ✅
ml:qdrant:upsert- Indexer des embeddings - ✅
ml:qdrant:search- Rechercher des embeddings similaires - ✅
ml:qdrant:delete- Supprimer des points
Exemple d'utilisation
// 1. Créer une collection
await workersQueueService.enqueueMlQdrantCreateCollection({
v: 1,
orgId: "org-uuid",
entityId: "collection-uuid",
collectionName: "sessions-embeddings",
vectorSize: 384, // Dimension des embeddings
distance: "Cosine",
});
// 2. Générer des embeddings et les indexer
const embeddings = await workersQueueService.enqueueMlEmbedTexts({
v: 1,
orgId: "org-uuid",
entityId: "batch-uuid",
texts: ["Session 1", "Session 2", "Session 3"],
});
// 3. Indexer les embeddings dans Qdrant
await workersQueueService.enqueueMlQdrantUpsert({
v: 1,
orgId: "org-uuid",
entityId: "upsert-uuid",
collectionName: "sessions-embeddings",
points: embeddings.embeddings.map((emb, idx) => ({
id: `session-${idx}`,
vector: emb,
payload: { text: texts[idx], orgId: "org-uuid" },
})),
});
// 4. Rechercher des embeddings similaires
await workersQueueService.enqueueMlQdrantSearch({
v: 1,
orgId: "org-uuid",
entityId: "search-uuid",
collectionName: "sessions-embeddings",
queryVector: queryEmbedding,
limit: 10,
scoreThreshold: 0.7,
filter: { orgId: "org-uuid" },
});
✅ Phase 3 : Recherche Sémantique dans les Sessions (Complétée)
Fonctionnalités implémentées
- ✅ SessionsSemanticSearchService : Service complet pour la recherche sémantique
- ✅ Endpoint API :
GET /api/sessions/search/semantic?q=... - ✅ Indexation automatique : Les nouvelles sessions sont indexées automatiquement
- ✅ Ré-indexation : Les sessions sont ré-indexées lors de modifications (title, notes, tags, etc.)
- ✅ Script de migration : Script pour indexer les sessions existantes
Utilisation
Recherche sémantique via API
GET /api/sessions/search/semantic?q=consultation%20anxiété&limit=10&scoreThreshold=0.7
Indexer les sessions existantes
npx tsx backend/src/sessions/scripts/index-sessions-for-semantic-search.ts <orgId> [batchSize]
Exemple de résultat
{
"query": "consultation anxiété",
"results": [
{
"session": { /* SessionWithRelations */ },
"score": 0.89
},
{
"session": { /* SessionWithRelations */ },
"score": 0.82
}
],
"count": 2
}
✅ Phase 3 : Recherche Sémantique dans les Sessions (Complétée)
Historique ML / phases anciennes : git (fichiers retirés de docs/).
✅ Phase 5 : OCR Avancé avec Python (Complétée)
Service OCR Python
- ✅ OCR Service : Service Python avec EasyOCR et PaddleOCR
- ✅ Endpoints API :
/api/ocr/extract,/api/ocr/extract-base64,/api/ocr/extract-simple - ✅ Processor BullMQ :
MlOcrProcessorpour traiter les jobsml:ocr - ✅ Intégration : Intégration avec le workflow OCR existant (fallback vers Tesseract.js)
Fonctionnalités
- ✅ Support multi-moteurs : EasyOCR (par défaut) et PaddleOCR
- ✅ Multi-langues : Support de plusieurs langues (en, fr, etc.)
- ✅ Détails optionnels : Bounding boxes et scores de confiance
- ✅ Fallback automatique : Si Python OCR échoue, utilise Tesseract.js
Configuration
# Activer/désactiver Vision OCR (GPT-4o) - par défaut: activé
USE_VISION_OCR=true
Utilisation
Le système utilise GPT-4o Vision API pour l'OCR si USE_VISION_OCR=true et si l'utilisateur a une clé API OpenAI configurée. En cas d'échec ou si l'utilisateur n'a pas de clé API, le système bascule automatiquement vers Tesseract.js.
Détails historiques ML : git.
Fonctionnalités implémentées
- ✅ SessionsSemanticSearchService : Service complet pour la recherche sémantique
- ✅ Endpoint API :
GET /api/sessions/search/semantic?q=... - ✅ Indexation automatique : Les nouvelles sessions sont indexées automatiquement
- ✅ Ré-indexation : Les sessions sont ré-indexées lors de modifications (title, notes, tags, etc.)
- ✅ Script de migration : Script pour indexer les sessions existantes