Error Correction Memory¶
1. Vue d'Ensemble¶
1.1 Concept¶
Error Correction Memory est un système d'apprentissage progressif qui mémorise les erreurs récurrentes de transcription et permet au LLM de les corriger automatiquement dans les futures transcriptions.
1.2 Problème Résolu¶
Les systèmes ASR (Whisper) font les MÊMES erreurs répétitives sur certains termes techniques ou spécialisés :
| Erreur Whisper | Correction Attendue | Domaine |
|---|---|---|
| "cooper nettys" | "kubernetes" | Tech |
| "doc air" | "Docker" | Tech |
| "react j s" | "React.js" | Tech |
| "pi tone" | "Python" | Tech |
| "post gré" | "PostgreSQL" | Tech |
| "git lab" | "GitLab" | Tech |
Constat : Sans mémoire, le LLM ne peut pas corriger ces patterns spécifiques de manière cohérente entre les transcriptions.
1.3 Solution¶
correct_text: "kubernetes"
frequency: 1 DB-->>API: Pattern sauvegardé Note over User,LLM: Transcription suivante LLM->>DB: retrieve_error_patterns(user_id) DB-->>LLM: ["cooper nettys" → "kubernetes" (freq: 5)] LLM->>LLM: Inject patterns in prompt Note right of LLM: ERREURS FREQUENTES:
'cooper nettys' → 'kubernetes' LLM-->>API: Transcription corrigée automatiquement
2. Architecture Technique¶
2.1 Modèle de Données¶
Table : transcription_errors
class TranscriptionError(Base):
"""
Error Correction Memory pour RAG v3.
Stocke les erreurs de transcription reportées par utilisateurs.
"""
__tablename__ = "transcription_errors"
# Identifiers
id = Column(String(36), primary_key=True)
user_id = Column(String(36), ForeignKey("users.id"), nullable=False, index=True)
transcript_id = Column(String(36), ForeignKey("transcripts.uuid"), nullable=True)
segment_id = Column(String(36), nullable=True)
# Error pattern
wrong_text = Column(String(500), nullable=False)
correct_text = Column(String(500), nullable=False)
# Pattern tracking
frequency = Column(Integer, default=1, nullable=False)
context = Column(String(100), nullable=True) # tech, medical, legal, business
# Metadata
confidence = Column(Float, nullable=True) # 0-1
first_seen = Column(String(50), nullable=True)
last_seen = Column(String(50), nullable=True)
# Timestamps
created_at = Column(String(50), nullable=False)
updated_at = Column(String(50), nullable=False)
Indexes optimisés :
- idx_errors_wrong_text : Recherche rapide par pattern
- idx_errors_user_id : Isolation utilisateur (RGPD)
- idx_errors_user_context_freq : Composite pour query fréquent
2.2 Service ErrorCorrectionMemory¶
Localisation : src/services/error_correction_memory.py
Méthode 1 : save_error_pattern()¶
def save_error_pattern(
wrong_text: str,
correct_text: str,
user_id: str,
db: Session,
transcript_id: Optional[str] = None,
segment_id: Optional[str] = None,
context: Optional[str] = None,
confidence: Optional[float] = None
) -> str
Logique Upsert :
1. Chercher pattern existant (wrong_text + user_id + context)
2. Si existe : INCREMENT frequency, UPDATE last_seen
3. Si n'existe pas : CREATE nouveau pattern
Exemple :
error_memory.save_error_pattern(
wrong_text="cooper nettys",
correct_text="kubernetes",
user_id="user_123",
db=db,
context="tech",
confidence=0.95 # Correction manuelle = haute confiance
)
Méthode 2 : retrieve_error_patterns()¶
def retrieve_error_patterns(
segment_texts: List[str],
user_id: str,
db: Session,
context: Optional[str] = None,
min_frequency: int = 2,
limit: int = 20
) -> List[Dict]
Stratégie de retrieval :
1. Query patterns pour user_id + context (optionnel)
2. Filtrer patterns où frequency >= min_frequency
3. Ordonner par frequency DESC (erreurs les plus communes en premier)
4. Limiter à top N patterns
Exemple de résultat :
[
{
"wrong_text": "cooper nettys",
"correct_text": "kubernetes",
"frequency": 15,
"context": "tech",
"confidence": 0.95
},
{
"wrong_text": "doc air",
"correct_text": "Docker",
"frequency": 8,
"context": "tech",
"confidence": 0.92
}
]
3. Intégration dans le Workflow¶
3.1 Phase 1 : Capture des Erreurs (NON INTÉGRÉ)¶
Workflow attendu - Édition de segment :
# Endpoint: PATCH /api/transcripts/{id}/segments
@router.patch("/{transcript_id}/segments")
async def update_segment(
transcript_id: str,
segment_data: dict,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
segment = get_segment_from_db(segment_data["segment_id"])
if "transcription" in segment_data:
old_text = segment.transcription
new_text = segment_data["transcription"]
# 1. Sauvegarder l'original (première modification)
if segment.original_transcription is None:
segment.original_transcription = old_text
# 2. Sauvegarder le pattern d'erreur
if old_text and new_text and old_text != new_text:
error_memory.save_error_pattern(
wrong_text=old_text,
correct_text=new_text,
user_id=current_user.id,
db=db,
transcript_id=transcript_id,
segment_id=segment.id,
context="tech", # Détecté automatiquement ou choisi par user
confidence=0.95 # Correction manuelle = haute confiance
)
logger.info(f"Error pattern saved for segment {segment.id}")
# 3. Mettre à jour le texte
segment.transcription = new_text
db.commit()
return {"status": "updated"}
Statut actuel : NON IMPLÉMENTÉ (Blocage critique - 30% restant)
3.2 Phase 2 : Utilisation des Patterns (IMPLÉMENTÉ)¶
Workflow actuel - LLMPostProcessor.clean_transcription() :
# Récupérer les patterns d'erreur de l'utilisateur
error_patterns = self.error_memory.retrieve_error_patterns(
segment_texts=segment_texts,
user_id=user_id,
db=db,
context="tech",
min_frequency=2,
limit=15
)
# Construire le contexte pour le prompt
if error_patterns:
pattern_lines = [
f"- '{p['wrong_text']}' → '{p['correct_text']}' (fréquence: {p['frequency']})"
for p in error_patterns[:10]
]
error_patterns_info = (
f"\n\nERREURS FREQUENTES DETECTEES (PRIORITE HAUTE - corrigez TOUJOURS):\n"
+ "\n".join(pattern_lines)
)
# Injecter dans le prompt LLM
prompt = f"""Tu es un assistant de nettoyage de transcriptions automatiques.
Tâche: Corriger et améliorer la transcription suivante (sortie Whisper).
{error_patterns_info}
{context_info}
{speaker_info}
Transcription à corriger:
{full_transcription}
"""
Statut actuel : IMPLÉMENTÉ et FONCTIONNEL
4. Impact Attendu¶
4.1 Benchmark Industrie¶
| Métrique | Valeur | Source |
|---|---|---|
| Amélioration WER | ~10% | GEC-RAG Paper (EMNLP) |
| Usage Industrie | ⅘ étoiles | Benchmark RAG Transcription |
| Réduction Coût LLM | ~15% tokens | Patterns connus = contexte plus court |
4.2 Progressive Learning¶
Erreurs: 10"] --> B["User corrige 5
Patterns sauvés: 5"] B --> C["Transcription 2
Erreurs: 7"] C --> D["User corrige 3
Patterns sauvés: 8"] D --> E["Transcription 3
Erreurs: 4"] E --> F["User corrige 1
Patterns sauvés: 9"] F --> G["Transcription 4
Erreurs: 2"] style A fill:#fee2e2,stroke:#dc2626 style C fill:#fef3c7,stroke:#f59e0b style E fill:#dbeafe,stroke:#3b82f6 style G fill:#d1fae5,stroke:#10b981
Constat : Plus le système est utilisé, moins il fait d'erreurs.
4.3 Isolation Utilisateur¶
Problème : Les termes techniques varient selon les domaines.
Solution : Patterns isolés par user_id + context
| User | Context | Pattern |
|---|---|---|
| user_tech_123 | tech | "doc air" → "Docker" |
| user_medical_456 | medical | "radiographie" → "Radiographie thoracique" |
| user_legal_789 | legal | "code civil" → "Code Civil" |
5. État de l'Implémentation¶
5.1 Ce qui est FAIT (70%)¶
- Table
transcription_errorsen base de données - Service
ErrorCorrectionMemorycomplet save_error_pattern()avec logique upsertretrieve_error_patterns()avec filtres optimisésget_patterns_by_user()pour admin/debug- Intégration dans LLMPostProcessor
- Récupération patterns avant cleaning
- Injection dans prompt avec PRIORITE HAUTE
- Tests unitaires complets (pytest)
- Indexes optimisés pour performance
5.2 Ce qui MANQUE (30%)¶
- Endpoint d'édition segments non intégré
- Pattern
wrong_text → correct_textjamais sauvegardé - Table
transcription_errorstoujours vide -
Apprentissage progressif INACTIF
-
Frontend UI pour visualiser patterns
- User ne voit pas ses corrections enregistrées
-
Pas de feedback loop visuel
-
Context detection automatique
- Actuellement hardcodé
context="tech" - Devrait détecter selon contenu (LLM ou règles)
6. Roadmap d'Implémentation¶
Phase 1 : Intégration Backend (PRIORITÉ CRITIQUE)¶
Effort estimé : 15-30 minutes
Impact : Débloque l'apprentissage progressif
Tâches :
1. Identifier endpoint d'édition segments (main.py ou router)
2. Importer get_error_correction_memory()
3. Ajouter logique de sauvegarde pattern dans endpoint
4. Ajouter champ original_transcription si manquant
5. Tester avec correction manuelle
Livrable : Table transcription_errors se remplit au fil des corrections
Phase 2 : Context Detection Automatique (RECOMMANDÉ)¶
Effort estimé : 2-3 heures
Impact : Patterns plus précis et contextualisés
Stratégies possibles :
Option A - Détection par LLM :
# Analyze first 5 segments to determine context
context = await llm_service.detect_context(segments[:5])
# Returns: "tech", "medical", "legal", "business", "general"
Option B - Détection par keywords :
tech_keywords = ["API", "Docker", "kubernetes", "Python", "React"]
medical_keywords = ["patient", "diagnostic", "traitement", "radiographie"]
if any(kw in transcription for kw in tech_keywords):
context = "tech"
elif any(kw in transcription for kw in medical_keywords):
context = "medical"
else:
context = "general"
Phase 3 : Frontend UI (OPTIONNEL)¶
Effort estimé : 2-3 jours
Impact : Transparence et confiance utilisateur
Features UI proposées :
7. Avantages Compétitifs¶
7.1 vs Otter.ai¶
| Fonctionnalité | Otter.ai | Smart Transcription |
|---|---|---|
| Custom Vocabulary | Pré-transcription | (futur) |
| Error Correction Memory | Non | 70% implémenté |
| Progressive Learning | Limité | Auto-increment frequency |
| Context-Specific | Non | tech/medical/legal |
7.2 vs Zoom AI Companion¶
| Fonctionnalité | Zoom | Smart Transcription |
|---|---|---|
| Error Patterns | Non | Oui |
| User-Specific Learning | Non | RGPD-compliant |
| Frequency Tracking | Non | Auto-increment |
7.3 Différenciation¶
Unique Selling Point : Système apprend des corrections utilisateur et améliore automatiquement les futures transcriptions sans intervention manuelle.
8. Monitoring et Métriques¶
8.1 KPIs à Tracker¶
# Métriques business
total_patterns = db.query(func.count(TranscriptionError.id)).scalar()
avg_frequency = db.query(func.avg(TranscriptionError.frequency)).scalar()
top_errors = db.query(TranscriptionError).order_by(TranscriptionError.frequency.desc()).limit(10)
# WER improvement estimation
corrections_applied = len([p for p in patterns if p['frequency'] >= 3])
estimated_wer_gain = corrections_applied * 0.002 # ~0.2% per common pattern
8.2 Dashboard Suggéré¶
| Métrique | Valeur Exemple | Cible |
|---|---|---|
| Patterns Totaux | 127 | > 50 |
| Patterns Fréquents (freq>=5) | 23 | > 10 |
| Fréquence Moyenne | 3.2 | > 2.0 |
| WER Gain Estimé | 4.6% | > 5% |
| Corrections Auto Appliquées | 89% | > 80% |
9. Références¶
9.1 Papers Académiques¶
- GEC-RAG: Generative Error Correction with Retrieval-Augmented Generation (EMNLP 2024)
- Whisper Error Patterns: Analysis of systematic transcription errors (OpenAI Research)
9.2 Benchmarks Industrie¶
- Otter.ai: Custom Vocabulary System
- AssemblyAI: Word Boost Feature
- Deepgram: Keywords Parameter
9.3 Documentation Interne¶
Conclusion¶
Error Correction Memory est une fonctionnalité stratégique pour :
- Améliorer continuellement la qualité des transcriptions (WER -10%)
- Différencier Smart Transcription de la concurrence
- Réduire les coûts LLM (contexte plus court)
- Améliorer l'expérience utilisateur (moins de corrections manuelles)
Statut actuel : Infrastructure prête (70%), intégration endpoint manquante (30%)
Prochaine étape : Intégrer save_error_pattern() dans l'endpoint d'édition segments (15-30 min)