Olivier CARON commited on
Commit
2a456fd
·
1 Parent(s): 782da57

Upload app and requirements files

Browse files
Files changed (2) hide show
  1. app.py +191 -0
  2. requirements.txt +7 -0
app.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ from transformers import pipeline
4
+ import plotly.graph_objects as go
5
+ import pandas as pd
6
+
7
+ # -----------------------------------------------------------------------------
8
+ # 1. Chargement du modèle (inchangé)
9
+ # -----------------------------------------------------------------------------
10
+ # Mettons le chargement dans un bloc try-except pour une meilleure gestion d'erreur
11
+ try:
12
+ classifier = pipeline(
13
+ "text-classification",
14
+ model="oliviercaron/fr-camembert-spplus-sentiment",
15
+ device_map="auto",
16
+ top_k=None
17
+ )
18
+ print("Modèle chargé avec succès.")
19
+ except Exception as e:
20
+ print(f"Erreur lors du chargement du modèle : {e}")
21
+ classifier = None
22
+
23
+ # -----------------------------------------------------------------------------
24
+ # 2. Fonction d'analyse (entièrement réécrite)
25
+ # -----------------------------------------------------------------------------
26
+ def analyze_sentiment(text: str):
27
+ """
28
+ Analyse le sentiment d'un texte et retourne une synthèse, un graphique
29
+ et un tableau détaillé des scores.
30
+ """
31
+ if not classifier:
32
+ # Gère le cas où le modèle n'a pas pu être chargé
33
+ return "Erreur : Le modèle d'analyse n'est pas disponible.", None, None
34
+
35
+ if not text or not text.strip():
36
+ # Retourne des valeurs vides pour réinitialiser l'interface
37
+ return None, None, None
38
+
39
+ # Obtenir les prédictions du modèle
40
+ results = classifier(text)[0]
41
+
42
+ # Trier les résultats par score (le plus élevé en premier)
43
+ results = sorted(results, key=lambda x: x['score'], reverse=True)
44
+
45
+ # --- Création du DataFrame pour le tableau de résultats ---
46
+ labels = [r['label'] for r in results]
47
+ scores_formatted = [f"{r['score'] * 100:.2f} %" for r in results]
48
+ emoji_map = {"Positif": "🟢", "Négatif": "🔴", "Neutre": "⚪"}
49
+ emojis = [emoji_map.get(label, "⚫") for label in labels]
50
+
51
+ # Le DataFrame que l'on affichera dans l'onglet "Scores Détaillés"
52
+ df_results = pd.DataFrame({
53
+ "": emojis,
54
+ "Sentiment": labels,
55
+ "Confiance": scores_formatted
56
+ })
57
+
58
+ # --- Création du graphique à barres Plotly ---
59
+ chart_scores = [r['score'] * 100 for r in results]
60
+ colors = ['#22c55e' if label == 'Positif' else '#ef4444' if label == 'Négatif' else '#6b7280' for label in labels]
61
+
62
+ fig = go.Figure(data=[
63
+ go.Bar(
64
+ x=labels, y=chart_scores, marker_color=colors,
65
+ text=[f'{s:.1f}%' for s in chart_scores], textposition='auto',
66
+ )
67
+ ])
68
+ fig.update_layout(
69
+ title_text="Distribution des Sentiments",
70
+ xaxis_title="Sentiment", yaxis_title="Confiance (%)",
71
+ yaxis=dict(range=[0, 100]),
72
+ template="plotly_white", height=350, font=dict(size=14)
73
+ )
74
+
75
+ # --- Création du texte de synthèse ---
76
+ top_prediction = results[0]
77
+ top_label_emoji = emoji_map.get(top_prediction['label'], "⚫")
78
+
79
+ confidence_level = "Très élevée" if top_prediction['score'] > 0.9 else \
80
+ "Élevée" if top_prediction['score'] > 0.7 else \
81
+ "Modérée" if top_prediction['score'] > 0.5 else "Faible"
82
+
83
+ summary_text = (
84
+ f"### {top_label_emoji} Prédiction principale : **{top_prediction['label']}**\n"
85
+ f"**Niveau de confiance :** {confidence_level} ({top_prediction['score']*100:.1f}%)"
86
+ )
87
+
88
+ # Retourner les 3 éléments qui correspondent aux sorties de l'interface
89
+ return summary_text, fig, df_results
90
+
91
+ # -----------------------------------------------------------------------------
92
+ # 3. Données pour l'interface (exemples et style)
93
+ # -----------------------------------------------------------------------------
94
+ # Les exemples sont bien choisis, on les garde.
95
+ examples = [
96
+ "Accueil très aimable, explications claires, je suis satisfait.",
97
+ "Personnel compétent et à l'écoute, démarche rapide et efficace.",
98
+ "Excellent service, je recommande vivement cette démarche en ligne.",
99
+ "Je n'ai pas d'avis particulier sur la question.",
100
+ "Le service était correct, sans plus.",
101
+ "RAS, tout s'est bien passé comme d'habitude.",
102
+ "Très déçu, aucune réponse à mes emails depuis des semaines.",
103
+ "Procédure beaucoup trop compliquée et inutilement longue.",
104
+ ]
105
+
106
+ # Le CSS est bien, on le garde
107
+ css = """
108
+ .gradio-container {
109
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
110
+ max-width: 1024px;
111
+ margin: auto;
112
+ }
113
+ .main-header {
114
+ text-align: center;
115
+ margin-bottom: 2rem;
116
+ }
117
+ """
118
+
119
+ # -----------------------------------------------------------------------------
120
+ # 4. Construction de l'interface Gradio (réorganisée avec onglets)
121
+ # -----------------------------------------------------------------------------
122
+ with gr.Blocks(css=css, theme=gr.themes.Soft(), title="Analyse de sentiment") as iface:
123
+
124
+ # --- En-tête ---
125
+ gr.HTML("""
126
+ <div class="main-header">
127
+ <h1>🇫🇷 Analyse de sentiment pour les Services Publics</h1>
128
+ <p style="font-size: 1.1rem; color: #4b5563;">
129
+ Analyse des retours usagers avec le modèle <strong>fr-camembert-spplus-sentiment</strong>
130
+ </p>
131
+ <p style="font-size: 0.9rem; color: #6b7280;">
132
+ <a href="https://huggingface.co/oliviercaron/fr-camembert-spplus-sentiment" target="_blank">🤗 Voir le modèle sur HuggingFace</a> |
133
+ <span>Données issues de la plateforme <a href="https://www.plus.transformation.gouv.fr/" target="_blank">Services Publics +</a></span>
134
+ </p>
135
+ </div>
136
+ """)
137
+
138
+ # --- Corps de l'application en 2 colonnes ---
139
+ with gr.Row(variant="panel"):
140
+ # --- Colonne de gauche (Entrée) ---
141
+ with gr.Column(scale=2):
142
+ gr.Markdown("### 1. Saisissez votre texte")
143
+ text_input = gr.Textbox(
144
+ label="Commentaire de l'usager",
145
+ placeholder="Ex: 'Très satisfait du service, réponse rapide et claire.'",
146
+ lines=5,
147
+ )
148
+
149
+ analyze_btn = gr.Button("🔍 Analyse du sentiment", variant="primary", scale=1)
150
+
151
+ gr.Markdown("### 💡 Ou testez avec des exemples")
152
+ # NOUVEAU : Utilisation de gr.Examples pour un code plus propre et une meilleure UI
153
+ gr.Examples(
154
+ examples=examples,
155
+ inputs=text_input,
156
+ label="Cliquez sur un exemple pour le tester",
157
+ examples_per_page=8
158
+ )
159
+
160
+ # --- Colonne de droite (Résultats avec onglets) ---
161
+ with gr.Column(scale=3):
162
+ gr.Markdown("### 2. Consultez les résultats")
163
+ with gr.Tabs():
164
+ # Onglet 1 : La vue principale et la plus simple
165
+ with gr.TabItem("📊 Synthèse", id=0):
166
+ summary_output = gr.Markdown(label="Conclusion de l'analyse")
167
+ chart_output = gr.Plot(label="Distribution des scores")
168
+
169
+ # Onglet 2 : Le tableau détaillé pour ceux qui veulent les chiffres précis
170
+ with gr.TabItem("📋 Scores détaillés", id=1):
171
+ dataframe_output = gr.DataFrame(
172
+ label="Tableau des probabilités par sentiment",
173
+ headers=["", "Sentiment", "Confiance"],
174
+ interactive=False,
175
+ row_count=(3, "fixed"),
176
+ col_count=(3, "fixed")
177
+ )
178
+
179
+ # --- Gestionnaire d'événement ---
180
+ analyze_btn.click(
181
+ fn=analyze_sentiment,
182
+ inputs=[text_input],
183
+ # L'ordre des sorties doit correspondre à l'ordre du 'return' de la fonction
184
+ outputs=[summary_output, chart_output, dataframe_output]
185
+ )
186
+
187
+ # -----------------------------------------------------------------------------
188
+ # 5. Lancement de l'application
189
+ # -----------------------------------------------------------------------------
190
+ if __name__ == "__main__":
191
+ iface.launch(debug=True)
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio
2
+ torch
3
+ transformers
4
+ pandas
5
+ plotly
6
+ sentencepiece
7
+ protobuf