Aller au contenu principal

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/local pour utilisateur non-root
  • Structure Python : app/config/__init__.py pour é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 check
  • GET /health/ready - Readiness check
  • POST /api/embeddings/text - Générer un embedding pour un texte
  • POST /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() et enqueueMlEmbedTexts()
  • Types et schémas : Payloads MlEmbedTextPayload et MlEmbedTextsPayload avec validation Zod
  • WorkerModule : Intégration du WorkerMlModule dans 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)

Voir PYTHON_ML_FEATURES_COMPLETE.md pour la documentation complète.

✅ 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 : MlOcrProcessor pour traiter les jobs ml: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.

Voir PYTHON_ML_FEATURES_COMPLETE.md pour tous les détails.

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

✅ Phase 4 : Fonctionnalités Avancées (Complétées)

Recherche Sémantique dans les Contacts

  • ContactsSemanticSearchService : Service complet
  • Endpoint API : GET /api/contacts/search/semantic?q=...
  • Indexation automatique : Création/modification/suppression

Suggestions de Sessions Similaires

  • Endpoint API : GET /api/sessions/:id/similar
  • Recommandations automatiques : Trouve des sessions similaires

Classification Automatique de Documents

  • DocumentsClassificationService : Service de classification
  • Endpoint API : POST /api/documents/:id/classify
  • Types supportés : INVOICE, CONTRACT, QUESTIONNAIRE, OTHER

Voir PYTHON_ML_FEATURES_COMPLETE.md pour tous les détails.

Phase 3 : Cas d'usage avancés ✅ (Complété)

  • ✅ Classification automatique de documents
  • ✅ Recherche sémantique dans les sessions/contacts
  • ✅ Recommandations basées sur les embeddings (sessions similaires)

Phase 4 : OCR Avancé ✅ (Complété)

  • ✅ Évaluation PaddleOCR vs EasyOCR (EasyOCR par défaut, PaddleOCR optionnel)
  • ✅ Service OCR Python implémenté (EasyOCR/PaddleOCR avec fallback Tesseract.js)
  • ✅ Comparaison avec Tesseract.js (fallback automatique si Python OCR échoue)

📚 Documentation

🎉 Conclusion

L'infrastructure de base pour la stack Python est maintenant opérationnelle. Le service Python peut générer des embeddings localement, réduisant les coûts OpenAI. L'architecture est prête pour l'intégration de Qdrant et d'autres fonctionnalités ML avancées.