choupi-faq-api / faq_loader.py
Loren's picture
Add /list endpoint
fb430b2
Raw
History Blame Contribute Delete
3.84 kB
"""Chargement et traitement des données FAQ à partir des fichiers CSV."""
import logging
from pathlib import Path
from typing import List, Tuple
import pandas as pd
logger = logging.getLogger(__name__)
class FAQEntry:
"""Représentation d'une entrée FAQ."""
def __init__(self, formulation: str, theme: str, response: str) -> None:
"""
Initialiser une entrée FAQ.
Args:
formulation: La question de la FAQ
theme: Le thème/catégorie de la FAQ
response: La réponse associée
"""
self.formulation: str = formulation
self.theme: str = theme
self.response: str = response
def load_faq_data(
formulations_path: str,
responses_path: str,
delimiter: str = ";"
) -> List[FAQEntry]:
"""
Charger et fusionner les données FAQ à partir de deux fichiers CSV.
Les fichiers sont joints via la colonne 'theme'.
Args:
formulations_path: Chemin vers faq_formulations.csv (colonnes: formulation, theme)
responses_path: Chemin vers faq_responses.csv (colonnes: theme, response)
delimiter: Délimiteur du CSV (par défaut: ";")
Returns:
Liste d'objets FAQEntry contenant formulation, theme et réponse
Raises:
FileNotFoundError: Si un fichier CSV n'existe pas
ValueError: Si les fichiers sont vides ou mal formés
"""
# Vérifier existence des fichiers
if not Path(formulations_path).exists():
raise FileNotFoundError(f"Fichier non trouvé: {formulations_path}")
if not Path(responses_path).exists():
raise FileNotFoundError(f"Fichier non trouvé: {responses_path}")
try:
# Charger les CSV
logger.info(f"Chargement formulations depuis: {formulations_path}")
df_formulations: pd.DataFrame = pd.read_csv(
formulations_path,
delimiter=delimiter,
encoding="utf-8"
)
logger.info(f"Chargement réponses depuis: {responses_path}")
df_responses: pd.DataFrame = pd.read_csv(
responses_path,
delimiter=delimiter,
encoding="utf-8"
)
# Valider les colonnes
required_cols_form = {"formulation", "theme"}
required_cols_resp = {"theme", "response"}
if not required_cols_form.issubset(df_formulations.columns):
raise ValueError(
f"Colonnes manquantes dans formulations. Attendu: {required_cols_form}, "
f"Trouvé: {set(df_formulations.columns)}"
)
if not required_cols_resp.issubset(df_responses.columns):
raise ValueError(
f"Colonnes manquantes dans réponses. Attendu: {required_cols_resp}, "
f"Trouvé: {set(df_responses.columns)}"
)
# Joindre les dataframes sur la colonne 'theme'
logger.info("Fusion des données par theme...")
df_merged: pd.DataFrame = df_formulations.merge(
df_responses,
on="theme",
how="inner"
)
if df_merged.empty:
raise ValueError("Aucune correspondance trouvée entre formulations et réponses")
# Créer les objets FAQEntry
faq_entries: List[FAQEntry] = [
FAQEntry(
formulation=row["formulation"].strip(),
theme=row["theme"].strip(),
response=row["response"].strip()
)
for _, row in df_merged.iterrows()
]
logger.info(f"✓ {len(faq_entries)} entrées FAQ chargées avec succès")
return faq_entries
except pd.errors.ParserError as e:
raise ValueError(f"Erreur lors du parsing du CSV: {e}")
except Exception as e:
logger.error(f"Erreur lors du chargement des FAQ: {e}")
raise