Skip to content

Commit eb97c39

Browse files
first commit
0 parents  commit eb97c39

8 files changed

Lines changed: 832 additions & 0 deletions

File tree

.gitignore

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*.pyo
5+
*.pyd
6+
*.pyc
7+
8+
# Virtual environments
9+
env/
10+
.venv/
11+
venv/
12+
ENV/
13+
14+
# Cache and data
15+
cache/
16+
*.pkl
17+
*.db
18+
*.sqlite3
19+
20+
# Logs
21+
*.log
22+
23+
# Environment variables
24+
.env
25+
.env.*
26+
27+
# Backup
28+
*.backup
29+
30+
31+
32+
33+

data/faq.json

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
[
2+
{
3+
"id": 1,
4+
"category": "compte",
5+
"question": "Comment créer un compte utilisateur ?",
6+
"answer": "Pour créer un compte, rendez-vous sur la page d'inscription, remplissez le formulaire avec votre email et mot de passe, puis validez votre compte via l'email de confirmation."
7+
},
8+
{
9+
"id": 2,
10+
"category": "compte",
11+
"question": "J'ai oublié mon mot de passe, que faire ?",
12+
"answer": "Sur la page de connexion, cliquez sur 'Mot de passe oublié'. Entrez votre email et vous recevrez un lien de réinitialisation dans les 5 minutes."
13+
},
14+
{
15+
"id": 3,
16+
"category": "paiement",
17+
"question": "Quels moyens de paiement acceptez-vous ?",
18+
"answer": "Nous acceptons les cartes bancaires (Visa, Mastercard, Amex), PayPal, Apple Pay et les virements SEPA pour les montants supérieurs à 500€."
19+
},
20+
{
21+
"id": 4,
22+
"category": "livraison",
23+
"question": "Quel est le délai de livraison standard ?",
24+
"answer": "Le délai de livraison standard est de 3 à 5 jours ouvrés en France métropolitaine. Livraison express disponible en 24-48h pour 9,90€ supplémentaires."
25+
},
26+
{
27+
"id": 5,
28+
"category": "support",
29+
"question": "Comment contacter le service client ?",
30+
"answer": "Notre service client est disponible par email à support@example.com, par téléphone au 01 23 45 67 89 (lun-ven 9h-18h) ou via le chat en direct sur notre site."
31+
},
32+
{
33+
"id": 6,
34+
"category": "produit",
35+
"question": "Puis-je retourner un produit ?",
36+
"answer": "Oui, vous disposez de 30 jours pour retourner un produit non utilisé dans son emballage d'origine. Les frais de retour sont à votre charge sauf en cas de défaut."
37+
},
38+
{
39+
"id": 7,
40+
"category": "abonnement",
41+
"question": "Comment fonctionne l'abonnement premium ?",
42+
"answer": "L'abonnement Premium coûte 9,99€/mois et offre la livraison gratuite illimitée, un accès prioritaire aux ventes et des réductions exclusives de 10% sur tous les produits."
43+
},
44+
{
45+
"id": 8,
46+
"category": "sécurité",
47+
"question": "Mes données personnelles sont-elles sécurisées ?",
48+
"answer": "Absolument. Nous utilisons un cryptage SSL 256 bits, nos serveurs sont certifiés ISO 27001, et nous sommes conformes au RGPD. Vos données ne sont jamais vendues à des tiers."
49+
},
50+
{
51+
"id": 9,
52+
"category": "livraison",
53+
"question": "Livrez-vous à l'international ?",
54+
"answer": "Oui, nous livrons dans plus de 50 pays. Les frais et délais varient selon la destination. Consultez notre page 'Livraison internationale' pour plus de détails."
55+
},
56+
{
57+
"id": 10,
58+
"category": "produit",
59+
"question": "Comment suivre ma commande ?",
60+
"answer": "Dès l'expédition, vous recevez un email avec un numéro de suivi. Vous pouvez suivre votre colis en temps réel depuis votre espace client ou sur le site du transporteur."
61+
},
62+
{"id": 11, "category": "compte", "question": "Puis-je modifier mon adresse email ?", "answer": "Oui, rendez-vous dans votre espace personnel, section 'Informations du compte', puis cliquez sur 'Modifier l'email'."},
63+
{"id": 12, "category": "compte", "question": "Comment supprimer mon compte ?", "answer": "Contactez le support via le formulaire de contact en précisant votre demande de suppression. Un email de confirmation vous sera envoyé."},
64+
{"id": 13, "category": "compte", "question": "Puis-je avoir plusieurs comptes avec la même adresse email ?", "answer": "Non, une adresse email ne peut être associée qu'à un seul compte utilisateur."},
65+
{"id": 14, "category": "paiement", "question": "Les paiements sont-ils sécurisés ?", "answer": "Oui, tous les paiements sont traités via des plateformes sécurisées et cryptées."},
66+
{"id": 15, "category": "paiement", "question": "Puis-je payer en plusieurs fois ?", "answer": "Le paiement en 3x sans frais est disponible pour toute commande supérieure à 150€. Choisissez l'option lors du paiement."},
67+
{"id": 16, "category": "paiement", "question": "Où trouver ma facture ?", "answer": "Vos factures sont disponibles dans votre espace client, rubrique 'Commandes'."},
68+
{"id": 17, "category": "livraison", "question": "Comment modifier mon adresse de livraison ?", "answer": "Vous pouvez modifier votre adresse avant l'expédition depuis votre espace client, section 'Adresses'."},
69+
{"id": 18, "category": "livraison", "question": "Que faire si mon colis est perdu ?", "answer": "Contactez notre service client avec votre numéro de commande. Nous ouvrirons une enquête auprès du transporteur."},
70+
{"id": 19, "category": "livraison", "question": "Proposez-vous la livraison en point relais ?", "answer": "Oui, la livraison en point relais est disponible lors du choix du mode de livraison."},
71+
{"id": 20, "category": "produit", "question": "Comment obtenir une facture pour mon achat ?", "answer": "Une facture est envoyée par email après chaque achat et reste accessible dans votre espace client."},
72+
{"id": 21, "category": "produit", "question": "Les produits sont-ils garantis ?", "answer": "Oui, tous nos produits bénéficient d'une garantie légale de 2 ans."},
73+
{"id": 22, "category": "produit", "question": "Comment signaler un produit défectueux ?", "answer": "Contactez le support avec une photo du produit et votre numéro de commande. Nous vous indiquerons la marche à suivre."},
74+
{"id": 23, "category": "abonnement", "question": "Comment résilier mon abonnement ?", "answer": "Vous pouvez résilier à tout moment depuis votre espace client, rubrique 'Abonnement'."},
75+
{"id": 24, "category": "abonnement", "question": "Puis-je changer de formule d'abonnement ?", "answer": "Oui, il est possible de passer d'une formule à une autre depuis votre espace client."},
76+
{"id": 25, "category": "abonnement", "question": "L'abonnement est-il sans engagement ?", "answer": "Oui, vous pouvez résilier à tout moment sans frais."},
77+
{"id": 26, "category": "support", "question": "Quels sont les horaires du support ?", "answer": "Notre support est disponible du lundi au vendredi de 9h à 18h (hors jours fériés)."},
78+
{"id": 27, "category": "support", "question": "Avez-vous une FAQ technique ?", "answer": "Oui, consultez notre rubrique 'Aide & Support' pour des guides et tutoriels techniques."},
79+
{"id": 28, "category": "support", "question": "Comment donner mon avis sur un produit ?", "answer": "Après réception de votre commande, vous recevrez un email pour laisser un avis ou vous pouvez le faire depuis la fiche produit."},
80+
{"id": 29, "category": "technique", "question": "Je rencontre un bug sur le site, que faire ?", "answer": "Essayez de vider le cache de votre navigateur. Si le problème persiste, contactez le support avec une capture d'écran."},
81+
{"id": 30, "category": "technique", "question": "Quels navigateurs sont compatibles ?", "answer": "Notre site est compatible avec Chrome, Firefox, Edge, Safari et Opera (versions récentes)."},
82+
{"id": 31, "category": "technique", "question": "Comment activer les notifications ?", "answer": "Activez les notifications dans les paramètres de votre compte ou via le pop-up lors de votre première visite."},
83+
{"id": 32, "category": "confidentialité", "question": "Comment exercer mon droit d'accès à mes données ?", "answer": "Envoyez une demande à privacy@example.com avec une copie de votre pièce d'identité."},
84+
{"id": 33, "category": "confidentialité", "question": "Puis-je demander la suppression de mes données ?", "answer": "Oui, faites-en la demande via votre espace client ou par email à privacy@example.com."},
85+
{"id": 34, "category": "confidentialité", "question": "Combien de temps mes données sont-elles conservées ?", "answer": "Vos données sont conservées pendant la durée légale nécessaire, puis supprimées ou anonymisées."},
86+
{"id": 35, "category": "application", "question": "Avez-vous une application mobile ?", "answer": "Oui, notre application est disponible sur iOS et Android. Téléchargez-la depuis l'App Store ou Google Play."},
87+
{"id": 36, "category": "application", "question": "Comment se connecter à l'application mobile ?", "answer": "Utilisez les mêmes identifiants que sur le site web."},
88+
{"id": 37, "category": "application", "question": "L'application mobile est-elle gratuite ?", "answer": "Oui, l'application est gratuite. Certaines fonctionnalités sont réservées aux abonnés Premium."},
89+
{"id": 38, "category": "sécurité", "question": "Comment signaler une tentative de phishing ?", "answer": "Transférez l'email suspect à abuse@example.com. Nous enquêterons rapidement."},
90+
{"id": 39, "category": "sécurité", "question": "Comment choisir un mot de passe sécurisé ?", "answer": "Utilisez au moins 12 caractères, mélangez lettres, chiffres et symboles, et évitez les mots du dictionnaire."},
91+
{"id": 40, "category": "sécurité", "question": "Proposez-vous l'authentification à deux facteurs ?", "answer": "Oui, activez-la dans les paramètres de sécurité de votre compte."},
92+
{"id": 41, "category": "commande", "question": "Comment annuler une commande ?", "answer": "Vous pouvez annuler une commande tant qu'elle n'est pas expédiée, depuis votre espace client."},
93+
{"id": 42, "category": "commande", "question": "Puis-je modifier une commande après validation ?", "answer": "Contactez rapidement le support. Si la commande n'est pas encore traitée, une modification est possible."},
94+
{"id": 43, "category": "commande", "question": "Je n'ai pas reçu ma commande, que faire ?", "answer": "Vérifiez le suivi colis. Si besoin, contactez le support avec votre numéro de commande."},
95+
{"id": 44, "category": "newsletter", "question": "Comment m'abonner à la newsletter ?", "answer": "Inscrivez-vous via le formulaire en bas de page ou dans votre espace client."},
96+
{"id": 45, "category": "newsletter", "question": "Comment me désabonner de la newsletter ?", "answer": "Cliquez sur le lien de désinscription présent en bas de chaque newsletter."},
97+
{"id": 46, "category": "newsletter", "question": "Quels avantages à s'abonner à la newsletter ?", "answer": "Vous recevez des offres exclusives, des nouveautés et des conseils personnalisés."},
98+
{"id": 47, "category": "programme fidélité", "question": "Comment fonctionne le programme de fidélité ?", "answer": "À chaque achat, cumulez des points à échanger contre des réductions ou des cadeaux."},
99+
{"id": 48, "category": "programme fidélité", "question": "Comment utiliser mes points fidélité ?", "answer": "Vos points sont utilisables lors du paiement, en sélectionnant l'option correspondante."},
100+
{"id": 49, "category": "programme fidélité", "question": "Mes points fidélité expirent-ils ?", "answer": "Oui, les points sont valables 12 mois à compter de la date d'obtention."},
101+
{"id": 50, "category": "général", "question": "Où trouver vos conditions générales de vente ?", "answer": "Elles sont consultables en bas de page, rubrique 'CGV'."},
102+
{"id": 51, "category": "général", "question": "Comment contacter le DPO (délégué à la protection des données) ?", "answer": "Envoyez un email à dpo@example.com pour toute question relative à la protection des données."}
103+
]

main.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
"""
2+
API FastAPI avec retrieval par embeddings et mémoire.
3+
Lancer avec : uvicorn main:app --reload
4+
"""
5+
import logging
6+
from typing import Optional, List
7+
from fastapi import FastAPI, HTTPException, Request
8+
from fastapi.middleware.cors import CORSMiddleware
9+
from fastapi.responses import HTMLResponse
10+
from fastapi.templating import Jinja2Templates
11+
from pydantic import BaseModel
12+
from retrieval_engine import RetrievalEngine
13+
from memory_manager import MemoryManager
14+
15+
# Config
16+
logging.basicConfig(level=logging.INFO)
17+
logger = logging.getLogger("chatbot")
18+
19+
app = FastAPI(
20+
title="Chatbot avec Retrieval",
21+
description="Bot intelligent avec embeddings et mémoire contextuelle",
22+
version="2.0.0"
23+
)
24+
25+
# CORS
26+
app.add_middleware(
27+
CORSMiddleware,
28+
allow_origins=["*"],
29+
allow_credentials=True,
30+
allow_methods=["*"],
31+
allow_headers=["*"],
32+
)
33+
34+
# Templates
35+
templates = Jinja2Templates(directory="templates")
36+
37+
# Modules internes
38+
retriever = RetrievalEngine(
39+
faq_path="data/faq.json",
40+
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2" # Modèle français
41+
)
42+
memory = MemoryManager(max_history=5)
43+
44+
# Schemas
45+
class ChatRequest(BaseModel):
46+
message: str
47+
user_id: str = "anonymous"
48+
include_context: bool = True
49+
50+
class ChatResponse(BaseModel):
51+
response: str
52+
confidence: float
53+
user_id: str
54+
matched_question: Optional[str] = None
55+
context_used: int = 0
56+
57+
class ConversationHistory(BaseModel):
58+
user_id: str
59+
history: List[dict]
60+
61+
# Routes API
62+
@app.get("/", response_class=HTMLResponse)
63+
async def home(request: Request):
64+
"""Page d’accueil de l’interface web."""
65+
return templates.TemplateResponse("index.html", {"request": request})
66+
67+
@app.post("/chat", response_model=ChatResponse)
68+
async def chat(request: ChatRequest):
69+
"""Traitement d’un message utilisateur."""
70+
try:
71+
# Récupérer l'historique (désactivé temporairement)
72+
history = memory.get_history(request.user_id)
73+
74+
# Recherche sans contexte (context_history = vide)
75+
result = retriever.get_best_match(
76+
query=request.message,
77+
context_history=[]
78+
)
79+
80+
# Enregistrer l'interaction dans la mémoire
81+
memory.add_interaction(
82+
user_id=request.user_id,
83+
user_message=request.message,
84+
bot_response=result["answer"],
85+
confidence=result["confidence"]
86+
)
87+
88+
return ChatResponse(
89+
response=result["answer"],
90+
confidence=result["confidence"],
91+
user_id=request.user_id,
92+
matched_question=result.get("matched_question"),
93+
context_used=0
94+
)
95+
96+
except Exception as e:
97+
logger.exception("Erreur dans /chat : %s", e)
98+
raise HTTPException(status_code=500, detail=str(e))
99+
100+
@app.get("/history/{user_id}", response_model=ConversationHistory)
101+
async def get_history(user_id: str):
102+
"""Récupérer l'historique d'un utilisateur."""
103+
history = memory.get_history(user_id)
104+
return ConversationHistory(user_id=user_id, history=history)
105+
106+
@app.delete("/history/{user_id}")
107+
async def clear_history(user_id: str):
108+
"""Effacer l'historique d'un utilisateur."""
109+
memory.clear_history(user_id)
110+
return {"message": f"Historique effacé pour {user_id}"}
111+
112+
@app.get("/metrics")
113+
async def get_metrics():
114+
"""Retourne les métriques du système."""
115+
return {
116+
"retriever": retriever.get_stats(),
117+
"cache": retriever.get_cache_stats(),
118+
"memory": memory.get_stats(),
119+
"index_size": len(retriever.faq_data),
120+
}
121+
122+
@app.on_event("shutdown")
123+
async def shutdown_event():
124+
"""Sauvegarde le cache à l'arrêt."""
125+
retriever.save_cache()
126+
logger.info("Application arrêtée proprement.")
127+
128+
if __name__ == "__main__":
129+
import uvicorn
130+
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

memory_manager.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""
2+
Gestion de la mémoire conversationnelle
3+
"""
4+
from typing import Dict, List
5+
from datetime import datetime
6+
from collections import defaultdict
7+
8+
class MemoryManager:
9+
"""Gère l'historique des conversations par utilisateur"""
10+
def __init__(self, max_history: int = 5):
11+
self.max_history = max_history
12+
self.conversations: Dict[str, List[Dict]] = defaultdict(list)
13+
self.stats = {
14+
"total_interactions": 0,
15+
"active_users": 0
16+
}
17+
18+
def add_interaction(
19+
self,
20+
user_id: str,
21+
user_message: str,
22+
bot_response: str,
23+
confidence: float
24+
):
25+
"""Ajoute une interaction à l'historique"""
26+
interaction = {
27+
"timestamp": datetime.now().isoformat(),
28+
"user_message": user_message,
29+
"bot_response": bot_response,
30+
"confidence": confidence
31+
}
32+
33+
self.conversations[user_id].append(interaction)
34+
35+
# Limiter la taille de l'historique
36+
if len(self.conversations[user_id]) > self.max_history:
37+
self.conversations[user_id] = self.conversations[user_id][-self.max_history:]
38+
39+
self.stats["total_interactions"] += 1
40+
self.stats["active_users"] = len(self.conversations)
41+
42+
def get_history(self, user_id: str) -> List[Dict]:
43+
"""Récupère l'historique d'un utilisateur"""
44+
return self.conversations.get(user_id, [])
45+
46+
def clear_history(self, user_id: str):
47+
"""Efface l'historique d'un utilisateur"""
48+
if user_id in self.conversations:
49+
del self.conversations[user_id]
50+
self.stats["active_users"] = len(self.conversations)
51+
52+
def get_stats(self) -> Dict:
53+
"""Retourne les statistiques"""
54+
return self.stats
55+
56+
def get_recent_topics(self, user_id: str, n: int = 3) -> List[str]:
57+
"""Extrait les N derniers sujets abordés"""
58+
history = self.get_history(user_id)
59+
return [item["user_message"] for item in history[-n:]]

requirements.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fastapi
2+
uvicorn
3+
pydantic
4+
sentence-transformers
5+
numpy
6+
torch
7+
pytest
8+
httpx

0 commit comments

Comments
 (0)