| | """ |
| | API d'Analyse de Sentiment - Serveur Backend Flask |
| | Utilise Hugging Face Transformers (100% gratuit, fonctionne hors ligne) |
| | - Modèle anglais : distilbert-base-uncased-finetuned-sst-2-english |
| | - Modèle multilingue : tabularisai/multilingual-sentiment-analysis |
| | """ |
| |
|
| | from flask import Flask, request, jsonify, render_template |
| | from flask_cors import CORS |
| | from transformers import pipeline |
| | import os |
| |
|
| | |
| | app = Flask(__name__) |
| |
|
| | |
| | CORS(app) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | print("⏳ Chargement des modèles... (première fois = quelques minutes)") |
| |
|
| | |
| | model_en = pipeline( |
| | "sentiment-analysis", |
| | model="distilbert-base-uncased-finetuned-sst-2-english" |
| | ) |
| |
|
| | |
| | model_multi = pipeline( |
| | "sentiment-analysis", |
| | model="tabularisai/multilingual-sentiment-analysis" |
| | ) |
| |
|
| | print("✅ Modèles chargés avec succès !") |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | def normalize_result(hf_result, text_lang): |
| | """ |
| | Convertit le résultat brut de Hugging Face en format unifié pour le frontend. |
| | hf_result : liste retournée par le pipeline, ex: [{'label': 'POSITIVE', 'score': 0.99}] |
| | text_lang : langue du texte pour choisir les labels d'affichage |
| | """ |
| |
|
| | label_raw = hf_result[0]["label"].upper() |
| | score = round(hf_result[0]["score"] * 100) |
| |
|
| | |
| | if any(p in label_raw for p in ["POSITIVE", "POS", "5 STARS", "4 STARS"]): |
| | sentiment = "positive" |
| | emoji = "😊" |
| | pos_score = score |
| | neg_score = 100 - score |
| | neu_score = 0 |
| | elif any(p in label_raw for p in ["NEGATIVE", "NEG", "1 STAR", "2 STARS"]): |
| | sentiment = "negative" |
| | emoji = "😠" |
| | pos_score = 100 - score |
| | neg_score = score |
| | neu_score = 0 |
| | else: |
| | sentiment = "neutral" |
| | emoji = "😐" |
| | pos_score = 30 |
| | neg_score = 30 |
| | neu_score = score |
| |
|
| | |
| | labels = { |
| | "ar": {"positive": "إيجابي", "negative": "سلبي", "neutral": "محايد", "mixed": "مختلط"}, |
| | "fr": {"positive": "Positif", "negative": "Négatif", "neutral": "Neutre", "mixed": "Mixte"}, |
| | "en": {"positive": "Positive", "negative": "Negative", "neutral": "Neutral", "mixed": "Mixed"}, |
| | "es": {"positive": "Positivo", "negative": "Negativo", "neutral": "Neutral", "mixed": "Mixto"}, |
| | "de": {"positive": "Positiv", "negative": "Negativ", "neutral": "Neutral", "mixed": "Gemischt"}, |
| | } |
| |
|
| | |
| | ui_lang = text_lang if text_lang in labels else "fr" |
| | lang_map = labels[ui_lang] |
| |
|
| | return { |
| | "sentiment" : sentiment, |
| | "emoji" : emoji, |
| | "label" : lang_map[sentiment], |
| | "sub" : f"Score de confiance : {score}%", |
| | "scores" : { |
| | "positive" : pos_score, |
| | "negative" : neg_score, |
| | "neutral" : neu_score |
| | }, |
| | "analysis" : f"Le modèle a détecté un sentiment {lang_map[sentiment].lower()} " |
| | f"avec un score de confiance de {score}%. " |
| | f"Ce résultat est basé sur l'analyse locale via Hugging Face Transformers.", |
| | "keywords" : [], |
| | "business" : f"Un sentiment {lang_map[sentiment].lower()} peut être utilisé " |
| | f"pour prioriser les retours clients et adapter la stratégie commerciale.", |
| | "detected_lang" : text_lang if text_lang != "auto" else "Détection automatique" |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | @app.route("/") |
| | def index(): |
| | return render_template("index.html") |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | @app.route("/api/analyze", methods=["POST"]) |
| | def analyze(): |
| | |
| | data = request.get_json() |
| |
|
| | |
| | if not data or "text" not in data: |
| | return jsonify({"error": "Aucun texte fourni"}), 400 |
| |
|
| | |
| | text = data.get("text", "").strip() |
| | text_lang = data.get("text_lang", "auto") |
| | model_type = data.get("model", "multi") |
| |
|
| | |
| | if not text: |
| | return jsonify({"error": "Le texte est vide"}), 400 |
| |
|
| | |
| | if len(text) > 512: |
| | text = text[:512] |
| |
|
| | try: |
| | |
| | if model_type == "en": |
| | |
| | hf_result = model_en(text) |
| | else: |
| | |
| | hf_result = model_multi(text) |
| |
|
| | |
| | result = normalize_result(hf_result, text_lang) |
| |
|
| | |
| | result["model_used"] = "English (DistilBERT)" if model_type == "en" else "Multilingue" |
| |
|
| | return jsonify(result) |
| |
|
| | except Exception as e: |
| | return jsonify({"error": str(e)}), 500 |
| |
|
| |
|
| | |
| | |
| | |
| | @app.route("/api/health", methods=["GET"]) |
| | def health(): |
| | return jsonify({ |
| | "status" : "ok", |
| | "models" : { |
| | "english" : "distilbert-base-uncased-finetuned-sst-2-english", |
| | "multilingual": "tabularisai/multilingual-sentiment-analysis" |
| | } |
| | }) |
| |
|
| |
|
| | |
| | |
| | |
| | if __name__ == "__main__": |
| | port = int(os.environ.get("PORT", 5000)) |
| | debug = os.environ.get("FLASK_DEBUG", "false").lower() == "true" |
| | print(f"🚀 Serveur démarré sur http://localhost:{port}") |
| | app.run(host="0.0.0.0", port=port, debug=debug) |
| |
|