File size: 4,114 Bytes
dada8b0 b67bf8f dada8b0 b67bf8f 47a39fd dada8b0 b67bf8f dada8b0 47a39fd dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 47a39fd b67bf8f dada8b0 47a39fd dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 47a39fd dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 47a39fd dada8b0 b67bf8f dada8b0 b67bf8f dada8b0 b67bf8f 47a39fd dada8b0 b67bf8f dada8b0 b67bf8f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | import os
import random
import torch
import pandas as pd
from functools import lru_cache
from flask import Flask, render_template, request, jsonify
from sentence_transformers import SentenceTransformer
from fastapi import FastAPI
from fastapi.middleware.wsgi import WSGIMiddleware
import uvicorn
# ===============================
# CONFIG HF
# ===============================
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CSV_DATA = os.path.join(BASE_DIR, "dataset_2026.csv")
EMB_FILE = os.path.join(BASE_DIR, "embeddings_questions.pt")
TOP_K_RECOMMANDATIONS = 5
DEVICE = "cpu" # ⛔ FORCÉ CPU (HF)
# ===============================
# FLASK APP
# ===============================
app = Flask(
__name__,
template_folder=os.path.join(BASE_DIR, "templates"),
static_folder=os.path.join(BASE_DIR, "static")
)
# ===============================
# LOAD MODEL (SAFE)
# ===============================
print("🔹 Loading model (CPU only)...")
model = SentenceTransformer(
"sentence-transformers/all-MiniLM-L6-v2",
device="cpu"
)
# ===============================
# LOAD DATASET
# ===============================
print("🔹 Loading dataset...")
df = pd.read_csv(CSV_DATA)
df = df.dropna(subset=["question"]).reset_index(drop=True)
questions = df["question"].astype(str).tolist()
NB_QUESTIONS = len(questions)
print(f"✅ Questions loaded: {NB_QUESTIONS}")
# ===============================
# LOAD / CREATE EMBEDDINGS
# ===============================
if os.path.exists(EMB_FILE):
print("🔹 Loading cached embeddings...")
emb_base = torch.load(EMB_FILE, map_location="cpu")
else:
print("🔹 Computing embeddings...")
emb_base = model.encode(
questions,
convert_to_tensor=True,
normalize_embeddings=True,
batch_size=32
)
torch.save(emb_base, EMB_FILE)
emb_base = emb_base.cpu()
# ===============================
# CACHE QUESTION EMBEDDING
# ===============================
@lru_cache(maxsize=500)
def encode_question_cached(q: str):
return model.encode(
q,
convert_to_tensor=True,
normalize_embeddings=True
).cpu()
# ===============================
# UTILS
# ===============================
def enrich_message(base):
return random.choice([
f"Bonne question 🙂 {base}",
f"Voici ce que je peux vous dire : {base}",
base
])
# ===============================
# CORE LOGIC
# ===============================
def process_question(question: str):
if not question.strip():
return {"response": "Veuillez poser une question."}
emb_q = encode_question_cached(question).unsqueeze(0)
scores = torch.matmul(emb_q, emb_base.T).squeeze(0)
values, indices = torch.topk(scores, k=min(TOP_K_RECOMMANDATIONS + 1, len(scores)))
best_idx = indices[0].item()
confidence = int(values[0].item() * 100)
if confidence < 50:
return {
"response": "Je ne suis pas sûr de la réponse.",
"confidence": confidence
}
return {
"response": enrich_message(df["rationale"].iloc[best_idx]),
"confidence": confidence,
"matched": df["question"].iloc[best_idx],
"intent": df["intent"].iloc[best_idx]
}
# ===============================
# ROUTES
# ===============================
@app.route("/")
def index():
return render_template("index.html")
@app.route("/ask", methods=["POST"])
def ask():
data = request.get_json() or {}
question = data.get("question", "")
return jsonify(process_question(question))
# ===============================
# FASTAPI WRAPPER (HF)
# ===============================
fastapi_app = FastAPI()
fastapi_app.mount("/", WSGIMiddleware(app))
# ===============================
# MAIN
# ===============================
if __name__ == "__main__":
port = int(os.environ.get("PORT", 7860))
print(f"🚀 Running on port {port}")
uvicorn.run(fastapi_app, host="0.0.0.0", port=port)
|