Aller au contenu

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

sequenceDiagram participant User as Utilisateur participant UI as Frontend participant API as Backend API participant DB as TranscriptionError Table participant LLM as LLM Post-Processor User->>UI: Écoute segment et détecte erreur User->>UI: Corrige "cooper nettys" → "kubernetes" UI->>API: PATCH /segments/{id} API->>DB: save_error_pattern() Note right of DB: wrong_text: "cooper nettys"
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

graph LR A["Transcription 1
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_errors en base de données
  • Service ErrorCorrectionMemory complet
  • save_error_pattern() avec logique upsert
  • retrieve_error_patterns() avec filtres optimisés
  • get_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_text jamais sauvegardé
  • Table transcription_errors toujours 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 :

graph TB subgraph Admin["Panneau Admin - Error Patterns"] A1["Liste patterns par fréquence"] A2["Statistiques: Total corrections, WER gain"] A3["Actions: Supprimer pattern, Modifier correction"] end subgraph User["Interface Utilisateur"] U1["Badge: +5 patterns appris"] U2["Tooltip: Voir corrections appliquées"] U3["Highlight: Texte auto-corrigé en vert"] end style Admin fill:#dbeafe,stroke:#3b82f6,stroke-width:2px style User fill:#d1fae5,stroke:#10b981,stroke-width:2px

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)