book-generator-orgmode/api_corrections.py

242 lines
No EOL
9.8 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
API pour traiter les requêtes de correction depuis la page web.
Ce script:
1. Fournit des endpoints pour appliquer des corrections au fichier livre.org
2. Permet d'ajouter des mots au dictionnaire personnalisé
3. Permet de marquer des erreurs comme "à ne pas traiter" dans le CSV
"""
import os
import re
import json
import csv
from flask import Flask, request, jsonify, Blueprint
# Créer un Blueprint pour l'API
corrections_api = Blueprint('corrections_api', __name__)
# Chemin vers les fichiers
LIVRE_PATH = 'livre.org'
DICT_PATH = 'dictionnaire_personnalise.txt'
CSV_PATH = 'resume_erreurs.csv'
@corrections_api.route('/api/corrections', methods=['POST'])
def handle_corrections():
"""Endpoint pour traiter les requêtes de correction."""
data = request.json
if not data or 'action' not in data:
return jsonify({'success': False, 'message': 'Action non spécifiée'}), 400
action = data['action']
if action == 'apply_correction':
return apply_correction(data)
elif action == 'ignore_error':
return ignore_error(data)
elif action == 'add_to_dictionary':
return add_to_dictionary(data)
else:
return jsonify({'success': False, 'message': 'Action non reconnue'}), 400
def apply_correction(data):
"""Applique une correction au fichier livre.org."""
# Vérifier les paramètres requis
required_params = ['error_type', 'chapter', 'error_index', 'correction']
if not all(param in data for param in required_params):
return jsonify({'success': False, 'message': 'Paramètres manquants'}), 400
error_type = data['error_type']
chapter = data['chapter']
error_index = data['error_index']
correction = data['correction']
try:
# Lire le contenu du fichier
with open(LIVRE_PATH, 'r', encoding='utf-8') as file:
content = file.read()
# Trouver la section du chapitre
chapter_pattern = r'^\*\* ' + re.escape(chapter) + r'$(.*?)(?=^\*\* |\Z)'
chapter_match = re.search(chapter_pattern, content, re.MULTILINE | re.DOTALL)
if not chapter_match:
return jsonify({'success': False, 'message': f'Chapitre "{chapter}" non trouvé'}), 404
chapter_content = chapter_match.group(1)
chapter_start = chapter_match.start()
chapter_end = chapter_match.end()
# Appliquer la correction en fonction du type d'erreur
if error_type == 'spelling':
# Charger les erreurs d'orthographe pour ce chapitre
errors = load_spelling_errors(chapter)
if error_index >= len(errors):
return jsonify({'success': False, 'message': 'Index d\'erreur invalide'}), 400
error = errors[error_index]
word = error['word']
# Remplacer le mot dans le contenu du chapitre
modified_chapter = re.sub(r'\b' + re.escape(word) + r'\b', correction, chapter_content)
# Mettre à jour le contenu complet
new_content = content[:chapter_start] + '** ' + chapter + modified_chapter + content[chapter_end:]
elif error_type == 'grammar':
# Charger les erreurs grammaticales pour ce chapitre
errors = load_grammar_errors(chapter)
if error_index >= len(errors):
return jsonify({'success': False, 'message': 'Index d\'erreur invalide'}), 400
error = errors[error_index]
error_text = error['error_text']
context = error['context']
# Trouver le contexte dans le chapitre
context_pattern = re.escape(context.replace(error_text, error_text))
context_match = re.search(context_pattern, chapter_content)
if not context_match:
return jsonify({'success': False, 'message': 'Contexte non trouvé dans le chapitre'}), 404
# Remplacer l'erreur dans le contexte
corrected_context = context.replace(error_text, correction)
# Remplacer le contexte dans le chapitre
modified_chapter = chapter_content.replace(context, corrected_context)
# Mettre à jour le contenu complet
new_content = content[:chapter_start] + '** ' + chapter + modified_chapter + content[chapter_end:]
else:
return jsonify({'success': False, 'message': 'Type d\'erreur non reconnu'}), 400
# Écrire le contenu modifié dans le fichier
with open(LIVRE_PATH, 'w', encoding='utf-8') as file:
file.write(new_content)
return jsonify({'success': True, 'message': 'Correction appliquée avec succès'})
except Exception as e:
return jsonify({'success': False, 'message': f'Erreur lors de l\'application de la correction: {str(e)}'}), 500
def ignore_error(data):
"""Marque une erreur comme 'à ne pas traiter' dans le CSV."""
# Vérifier les paramètres requis
required_params = ['error_type', 'chapter', 'error_index']
if not all(param in data for param in required_params):
return jsonify({'success': False, 'message': 'Paramètres manquants'}), 400
error_type = data['error_type']
chapter = data['chapter']
error_index = data['error_index']
try:
# Lire le CSV des erreurs
rows = []
with open(CSV_PATH, 'r', newline='', encoding='utf-8') as csvfile:
reader = csv.reader(csvfile)
headers = next(reader) # Lire les en-têtes
# Ajouter les en-têtes à la liste des lignes
rows.append(headers)
# Parcourir les lignes et mettre à jour celle du chapitre concerné
for row in reader:
if len(row) > 0 and row[0] == chapter:
# Mettre à jour la ligne en fonction du type d'erreur
if error_type == 'spelling' and len(row) > 1:
# Décrémenter le nombre d'erreurs d'orthographe
spelling_errors = int(row[1]) - 1
row[1] = str(max(0, spelling_errors))
# Mettre à jour le total
if len(row) > 3:
row[3] = str(int(row[3]) - 1)
elif error_type == 'grammar' and len(row) > 2:
# Décrémenter le nombre d'erreurs grammaticales
grammar_errors = int(row[2]) - 1
row[2] = str(max(0, grammar_errors))
# Mettre à jour le total
if len(row) > 3:
row[3] = str(int(row[3]) - 1)
rows.append(row)
# Écrire les modifications dans le CSV
with open(CSV_PATH, 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
writer.writerows(rows)
return jsonify({'success': True, 'message': 'Erreur ignorée avec succès'})
except Exception as e:
return jsonify({'success': False, 'message': f'Erreur lors de l\'ignorance de l\'erreur: {str(e)}'}), 500
def add_to_dictionary(data):
"""Ajoute un mot au dictionnaire personnalisé."""
# Vérifier les paramètres requis
if 'word' not in data:
return jsonify({'success': False, 'message': 'Mot non spécifié'}), 400
word = data['word']
try:
# Vérifier si le mot est déjà dans le dictionnaire
existing_words = set()
if os.path.exists(DICT_PATH):
with open(DICT_PATH, 'r', encoding='utf-8') as file:
for line in file:
line = line.strip()
if line and not line.startswith('#'):
existing_words.add(line.lower())
# Si le mot n'est pas déjà dans le dictionnaire, l'ajouter
if word.lower() not in existing_words:
with open(DICT_PATH, 'a', encoding='utf-8') as file:
file.write(f"\n{word}")
return jsonify({'success': True, 'message': 'Mot ajouté au dictionnaire avec succès'})
except Exception as e:
return jsonify({'success': False, 'message': f'Erreur lors de l\'ajout du mot au dictionnaire: {str(e)}'}), 500
def load_spelling_errors(chapter):
"""Charge les erreurs d'orthographe pour un chapitre donné depuis le rapport."""
# Cette fonction devrait charger les erreurs d'orthographe depuis le rapport
# Pour simplifier, nous utilisons une implémentation fictive
# Dans une implémentation réelle, il faudrait parser le rapport d'erreurs
# Exemple d'implémentation fictive
from generate_corrections_page import parse_error_report
errors_by_chapter = parse_error_report('rapport_orthographe_grammaire.md')
if chapter in errors_by_chapter:
return errors_by_chapter[chapter]['spelling']
return []
def load_grammar_errors(chapter):
"""Charge les erreurs grammaticales pour un chapitre donné depuis le rapport."""
# Cette fonction devrait charger les erreurs grammaticales depuis le rapport
# Pour simplifier, nous utilisons une implémentation fictive
# Dans une implémentation réelle, il faudrait parser le rapport d'erreurs
# Exemple d'implémentation fictive
from generate_corrections_page import parse_error_report
errors_by_chapter = parse_error_report('rapport_orthographe_grammaire.md')
if chapter in errors_by_chapter:
return errors_by_chapter[chapter]['grammar']
return []
# Pour tester l'API indépendamment
if __name__ == '__main__':
app = Flask(__name__)
app.register_blueprint(corrections_api)
app.run(debug=True, port=5001)