book-generator-orgmode/CONTEXT_MATCHING_FIX.md
2025-08-30 23:10:43 +02:00

6 KiB

Correction API - Context Matching Fix

Problème résolu

L'API de corrections (api_corrections.py) ne parvenait pas à trouver le contexte des erreurs grammaticales dans les chapitres. Spécifiquement, lorsqu'un utilisateur tentait d'appliquer une correction avec le payload suivant :

{
  "action": "apply_correction",
  "error_type": "grammar",
  "chapter": "Chapitre 1",
  "error_index": 2,
  "correction": "voir :"
}

L'API retournait une erreur 404 avec le message "Contexte non trouvé dans le chapitre".

Cause du problème

Le problème était dû à deux facteurs principaux :

  1. Recherche de contexte trop stricte : L'API utilisait une correspondance exacte pour trouver le contexte de l'erreur dans le chapitre, sans tenir compte des variations possibles dans les espaces, la ponctuation ou le formatage.

  2. Différences entre le rapport et le fichier source : Le contexte stocké dans le rapport d'erreurs pouvait différer légèrement du texte réel dans le fichier livre.org, notamment en ce qui concerne les espaces et la troncature du texte.

Solution implémentée

1. Amélioration de la recherche de contexte

Nous avons implémenté une approche de recherche de contexte à plusieurs niveaux, du plus strict au plus flexible :

# 1. Échapper les caractères spéciaux dans le contexte
escaped_context = re.escape(context)
# 2. Remplacer les espaces échappées par un motif qui accepte plusieurs espaces
flexible_context = escaped_context.replace('\\ ', '\\s+')
# 3. Créer un motif qui permet des variations
flexible_pattern = flexible_context

# Essayer d'abord avec le motif flexible
context_match = re.search(flexible_pattern, chapter_content)

2. Stratégies de fallback

Si la première approche échoue, nous utilisons des stratégies de fallback de plus en plus flexibles :

# Si ça ne fonctionne pas, essayer avec une approche encore plus flexible
if not context_match:
    # Extraire les mots significatifs du contexte (ignorer les mots très courts)
    words = [word for word in re.findall(r'\b\w+\b', context) if len(word) > 3]
    if words:
        # Créer un motif qui recherche une phrase contenant ces mots dans l'ordre
        words_pattern = r'.*'.join([re.escape(word) for word in words])
        context_match = re.search(words_pattern, chapter_content)

# Si toujours pas de correspondance, essayer de trouver juste l'erreur et son contexte immédiat
if not context_match and error_text:
    # Chercher l'erreur avec quelques mots avant et après
    error_vicinity = r'[^\n]{0,30}' + re.escape(error_text) + r'[^\n]{0,30}'
    context_match = re.search(error_vicinity, chapter_content)

3. Amélioration du remplacement de texte

Une fois le contexte trouvé, nous avons également amélioré la logique de remplacement pour gérer différents scénarios :

# Déterminer quelle stratégie de remplacement utiliser
if matched_text == context:
    # Si le texte correspond exactement au contexte, utiliser la méthode simple
    corrected_context = context.replace(error_text, correction)
    modified_chapter = chapter_content.replace(matched_text, corrected_context)
else:
    # Si nous avons utilisé une correspondance flexible, nous devons être plus précis
    # Trouver la position de l'erreur dans le contexte original
    error_pos = context.find(error_text)
    if error_pos >= 0:
        # Essayer de trouver l'erreur exacte dans le texte trouvé
        error_in_match = re.search(re.escape(error_text), matched_text)
        if error_in_match:
            # Remplacer directement l'erreur dans le texte trouvé
            start, end = error_in_match.span()
            corrected_matched_text = matched_text[:start] + correction + matched_text[end:]
            modified_chapter = chapter_content.replace(matched_text, corrected_matched_text)
        else:
            # Fallback: remplacer tout le texte trouvé
            corrected_context = context.replace(error_text, correction)
            modified_chapter = chapter_content.replace(matched_text, corrected_context)

4. Ajout d'informations de débogage

Nous avons ajouté des logs détaillés pour faciliter le diagnostic des problèmes :

# Ajouter des logs pour le débogage
print(f"Correction appliquée: '{error_text}' -> '{correction}'")
print(f"Contexte trouvé: '{matched_text}'")
print(f"Contexte après correction: '{corrected_context if 'corrected_context' in locals() else 'N/A'}'")

# Si le chapitre n'a pas été modifié, c'est qu'il y a un problème
if modified_chapter == chapter_content:
    print("AVERTISSEMENT: Le chapitre n'a pas été modifié après la correction!")

En cas d'échec, l'API retourne également des informations de débogage détaillées :

return jsonify({
    'success': False, 
    'message': 'Contexte non trouvé dans le chapitre',
    'debug_info': {
        'context': context,
        'error_text': error_text,
        'correction': correction,
        'chapter_excerpt': chapter_content[:200]  # Premiers 200 caractères du chapitre
    }
}), 404

Résultat

Avec ces modifications, l'API peut maintenant trouver et corriger correctement les erreurs grammaticales, même lorsque le contexte exact ne correspond pas parfaitement au texte du chapitre. Le test avec le payload spécifique mentionné dans la description du problème fonctionne désormais correctement.

Améliorations futures possibles

  1. Mise en cache des correspondances : Pour améliorer les performances, on pourrait mettre en cache les correspondances entre les contextes d'erreur et les positions dans le fichier.

  2. Interface utilisateur pour les erreurs : Ajouter une interface utilisateur pour afficher les erreurs de correspondance et permettre à l'utilisateur de sélectionner manuellement le texte à corriger.

  3. Normalisation des rapports : Modifier le processus de génération des rapports d'erreurs pour stocker plus d'informations sur le contexte exact, comme les positions des erreurs dans le fichier.