Anwaree commited on
Commit
d64b230
·
verified ·
1 Parent(s): 13496b3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +20 -432
app.py CHANGED
@@ -1,436 +1,24 @@
1
  import gradio as gr
2
- import joblib
3
- import numpy as np
4
- import pandas as pd
5
- import re
6
- import pickle
7
- import nltk
8
- from nltk.corpus import stopwords
9
- from nltk.stem import PorterStemmer
10
 
11
- # Télécharger les ressources NLTK nécessaires
12
- try:
13
- nltk.data.find('corpora/stopwords')
14
- except LookupError:
15
- nltk.download('stopwords')
16
 
17
- # =============================================================================
18
- # CHARGEMENT DES MODÈLES ET CONFIGURATION
19
- # =============================================================================
20
-
21
- def load_models():
22
- """Charger tous les modèles et configurations"""
23
- try:
24
- print("🔄 Chargement des modèles...")
25
-
26
- # Charger le modèle et le vectorizer
27
- model = joblib.load('spam_classifier.pkl')
28
- vectorizer = joblib.load('tfidf_vectorizer.pkl')
29
-
30
- # Charger la configuration de preprocessing
31
- with open('preprocessing_config.pkl', 'rb') as f:
32
- config = pickle.load(f)
33
-
34
- # Recréer les outils NLTK
35
- stop_words = set(config['stop_words'])
36
- stemmer = PorterStemmer()
37
-
38
- print("✅ Modèles chargés avec succès!")
39
- return model, vectorizer, stop_words, stemmer
40
-
41
- except FileNotFoundError as e:
42
- print(f"❌ Fichier manquant: {e}")
43
- print("🔧 Utilisation des paramètres par défaut...")
44
-
45
- # Paramètres par défaut si les fichiers sont manquants
46
- model = None
47
- vectorizer = None
48
- stop_words = set(stopwords.words('english'))
49
- stemmer = PorterStemmer()
50
-
51
- return model, vectorizer, stop_words, stemmer
52
-
53
- except Exception as e:
54
- print(f"❌ Erreur lors du chargement: {e}")
55
- return None, None, None, None
56
-
57
- # Charger tout au démarrage
58
- MODEL, VECTORIZER, STOP_WORDS, STEMMER = load_models()
59
-
60
- # =============================================================================
61
- # FONCTIONS DE PREPROCESSING (IDENTIQUES À VOTRE NOTEBOOK)
62
- # =============================================================================
63
-
64
- def preprocess_spam(text):
65
- """
66
- Préprocessing spécifique au spam - EXACTEMENT comme dans votre notebook
67
- Garde les ponctuations importantes : ! / + >
68
- """
69
- if pd.isna(text) or not text:
70
- return ""
71
-
72
- text = str(text).lower()
73
-
74
- # Supprimer URLs, emails, téléphones
75
- text = re.sub(r'http\S+|www\S+', '', text)
76
- text = re.sub(r'\S+@\S+', '', text)
77
- text = re.sub(r'\+?\d[\d -]{8,}\d', '', text)
78
-
79
- # Garder lettres et ponctuations importantes pour spam
80
- text = re.sub(r'[^a-z\s!/+>]', '', text)
81
-
82
- # Stemming et suppression stopwords
83
- if STEMMER and STOP_WORDS:
84
- words = [STEMMER.stem(word) for word in text.split() if word not in STOP_WORDS and word.strip()]
85
- else:
86
- words = text.split()
87
-
88
- return " ".join(words)
89
-
90
- def preprocess_ham(text):
91
- """
92
- Préprocessing spécifique au ham - EXACTEMENT comme dans votre notebook
93
- Supprime toute ponctuation
94
- """
95
- if pd.isna(text) or not text:
96
- return ""
97
-
98
- text = str(text).lower()
99
-
100
- # Supprimer URLs, emails, téléphones
101
- text = re.sub(r'http\S+|www\S+', '', text)
102
- text = re.sub(r'\S+@\S+', '', text)
103
- text = re.sub(r'\+?\d[\d -]{8,}\d', '', text)
104
-
105
- # Supprimer toute ponctuation
106
- text = re.sub(r'[^\w\s]', '', text)
107
-
108
- # Stemming et suppression stopwords
109
- if STEMMER and STOP_WORDS:
110
- words = [STEMMER.stem(word) for word in text.split() if word not in STOP_WORDS and word.strip()]
111
- else:
112
- words = text.split()
113
-
114
- return " ".join(words)
115
-
116
- # =============================================================================
117
- # FONCTION DE CLASSIFICATION PRINCIPALE
118
- # =============================================================================
119
-
120
- def classify_message(message, threshold=0.4):
121
- """
122
- Classification d'un message - BASÉE sur votre fonction test_message()
123
- """
124
- if not MODEL or not VECTORIZER:
125
- return "❌ Modèle non disponible. Vérifiez que les fichiers .pkl sont uploadés."
126
-
127
- try:
128
- if not message or not message.strip():
129
- return "⚠️ Veuillez entrer un message à analyser."
130
-
131
- # Preprocessing (utiliser preprocess_spam pour tous comme dans votre notebook)
132
- cleaned_message = preprocess_spam(message)
133
-
134
- if not cleaned_message.strip():
135
- return "⚠️ Le message ne contient pas de mots valides après nettoyage."
136
-
137
- # Vectorisation TF-IDF
138
- message_vector = VECTORIZER.transform([cleaned_message])
139
-
140
- # Prédiction des probabilités
141
- probabilities = MODEL.predict_proba(message_vector)[0]
142
- prob_ham = probabilities[0]
143
- prob_spam = probabilities[1]
144
-
145
- # Classification selon le seuil (comme votre fonction)
146
- prediction = 'spam' if prob_spam >= threshold else 'ham'
147
- confidence = prob_spam if prediction == 'spam' else prob_ham
148
-
149
- # Formatage du résultat
150
- if prediction == 'spam':
151
- result = "🚨 **SPAM DÉTECTÉ**\n"
152
- icon = "🔴"
153
- else:
154
- result = "✅ **MESSAGE LÉGITIME**\n"
155
- icon = "🟢"
156
-
157
- result += f"Confiance: **{confidence:.1%}**\n\n"
158
- result += f"📊 **Détails des probabilités:**\n"
159
- result += f"• {icon} Ham (légitime): {prob_ham:.1%}\n"
160
- result += f"• 🔴 Spam: {prob_spam:.1%}\n\n"
161
- result += f"🧹 **Message nettoyé:** `{cleaned_message}`\n"
162
- result += f"⚙️ **Seuil utilisé:** {threshold}"
163
-
164
- return result
165
-
166
- except Exception as e:
167
- return f"❌ Erreur lors de l'analyse: {str(e)}"
168
-
169
- def classify_csv_batch(file, threshold=0.4):
170
- """
171
- Classification par lot depuis un fichier CSV
172
- """
173
- if not MODEL or not VECTORIZER:
174
- return "❌ Modèle non disponible."
175
-
176
- try:
177
- # Lire le fichier CSV
178
- df = pd.read_csv(file.name)
179
-
180
- # Vérifications
181
- if 'message' not in df.columns:
182
- return "❌ Le fichier CSV doit contenir une colonne 'message'"
183
-
184
- if df.empty:
185
- return "❌ Le fichier CSV est vide"
186
-
187
- # Preprocessing de tous les messages
188
- df['cleaned'] = df['message'].astype(str).apply(preprocess_spam)
189
-
190
- # Supprimer les messages vides après nettoyage
191
- df_filtered = df[df['cleaned'].str.strip() != ""].copy()
192
-
193
- if df_filtered.empty:
194
- return "❌ Aucun message valide après nettoyage"
195
-
196
- # Vectorisation
197
- messages_vector = VECTORIZER.transform(df_filtered['cleaned'])
198
-
199
- # Prédictions
200
- probabilities = MODEL.predict_proba(messages_vector)
201
- spam_probs = probabilities[:, 1]
202
- ham_probs = probabilities[:, 0]
203
-
204
- # Classification avec seuil
205
- predictions = ['spam' if prob >= threshold else 'ham' for prob in spam_probs]
206
- confidences = [max(spam_probs[i], ham_probs[i]) for i in range(len(spam_probs))]
207
-
208
- # Ajouter les résultats
209
- df_filtered['prediction'] = predictions
210
- df_filtered['confidence'] = confidences
211
- df_filtered['prob_ham'] = ham_probs
212
- df_filtered['prob_spam'] = spam_probs
213
- df_filtered['threshold_used'] = threshold
214
-
215
- # Statistiques
216
- total_messages = len(df_filtered)
217
- spam_count = sum(1 for pred in predictions if pred == 'spam')
218
- ham_count = total_messages - spam_count
219
-
220
- print(f"📊 Résultats: {spam_count} spam, {ham_count} ham sur {total_messages} messages")
221
-
222
- # Sauvegarder
223
- output_filename = "spam_classification_results.csv"
224
- df_filtered.to_csv(output_filename, index=False)
225
-
226
- return output_filename
227
-
228
- except Exception as e:
229
- return f"❌ Erreur lors du traitement: {str(e)}"
230
-
231
- # =============================================================================
232
- # INTERFACE GRADIO
233
- # =============================================================================
234
-
235
- def create_interface():
236
- """Créer l'interface Gradio"""
237
-
238
- with gr.Blocks(
239
- title="🔍 Détecteur de Spam - ML",
240
- theme=gr.themes.Soft(),
241
- css="""
242
- .gradio-container {
243
- max-width: 1200px;
244
- margin: auto;
245
- }
246
- """
247
- ) as demo:
248
-
249
- gr.Markdown("""
250
- # 🔍 Détecteur de Spam Intelligent
251
- ### Classification automatique de messages avec Machine Learning
252
-
253
- Modèle basé sur **régression logistique** + **TF-IDF** entraîné sur des données SMS/emails réelles.
254
- """)
255
-
256
- # Tab 1: Classification individuelle
257
- with gr.Tab("📝 Analyse individuelle"):
258
- gr.Markdown("### Analysez un message texte")
259
-
260
- with gr.Row():
261
- with gr.Column(scale=3):
262
- message_input = gr.Textbox(
263
- label="📨 Message à analyser",
264
- placeholder="Tapez ou collez votre message ici...",
265
- lines=4,
266
- max_lines=10
267
- )
268
-
269
- threshold_slider = gr.Slider(
270
- minimum=0.1,
271
- maximum=0.9,
272
- value=0.4,
273
- step=0.05,
274
- label="🎯 Seuil de détection spam",
275
- info="Plus bas = plus sensible aux spams"
276
- )
277
-
278
- analyze_btn = gr.Button(
279
- "🔍 Analyser le message",
280
- variant="primary",
281
- size="lg"
282
- )
283
-
284
- with gr.Column(scale=3):
285
- result_output = gr.Textbox(
286
- label="📋 Résultat de l'analyse",
287
- lines=12,
288
- max_lines=20
289
- )
290
-
291
- # Exemples de test
292
- gr.Markdown("### 💡 Exemples à tester")
293
-
294
- examples_data = [
295
- ["Salut ! Comment ça va ? On se voit ce soir pour le dîner ?"],
296
- ["FÉLICITATIONS! Vous avez gagné 1000€! Cliquez MAINTENANT: http://win-money.fake"],
297
- ["Rappel: RDV médecin demain 14h30. Merci de confirmer."],
298
- ["URGENT! Your account will be closed! Click here: http://bank-fake.com"],
299
- ["FREE iPhone 15 PRO!!! 🎉 Limited offer! Call +1-800-FAKE now!!!"],
300
- ["Merci pour la réunion. Voici le compte-rendu en pièce jointe."],
301
- ["WINNER! You've been selected! Claim $5000 prize NOW! Text STOP to opt out"]
302
- ]
303
-
304
- gr.Examples(
305
- examples=examples_data,
306
- inputs=message_input,
307
- outputs=result_output,
308
- fn=lambda msg: classify_message(msg, 0.4),
309
- cache_examples=False
310
- )
311
-
312
- # Connecter les actions
313
- analyze_btn.click(
314
- fn=classify_message,
315
- inputs=[message_input, threshold_slider],
316
- outputs=result_output
317
- )
318
-
319
- # Tab 2: Classification par lot
320
- with gr.Tab("📊 Analyse par lot (CSV)"):
321
- gr.Markdown("""
322
- ### Analysez plusieurs messages en une fois
323
-
324
- **📋 Format CSV requis:**
325
- - Colonne `message` avec les textes à analyser
326
- - Encodage UTF-8 recommandé
327
- - Une ligne par message
328
- """)
329
-
330
- with gr.Row():
331
- with gr.Column():
332
- file_input = gr.File(
333
- label="📁 Fichier CSV à analyser",
334
- file_types=[".csv"],
335
- type="filepath"
336
- )
337
-
338
- threshold_csv = gr.Slider(
339
- minimum=0.1,
340
- maximum=0.9,
341
- value=0.4,
342
- step=0.05,
343
- label="🎯 Seuil de détection spam",
344
- info="Appliqué à tous les messages"
345
- )
346
-
347
- process_btn = gr.Button(
348
- "🔄 Traiter le fichier",
349
- variant="primary"
350
- )
351
-
352
- with gr.Column():
353
- file_output = gr.File(
354
- label="📥 Résultats (CSV à télécharger)",
355
- type="filepath"
356
- )
357
-
358
- gr.Markdown("""
359
- **📊 Le fichier de résultat contiendra:**
360
- - Vos messages originaux
361
- - Prédictions (spam/ham)
362
- - Probabilités détaillées
363
- - Messages nettoyés
364
- - Niveau de confiance
365
- """)
366
-
367
- process_btn.click(
368
- fn=classify_csv_batch,
369
- inputs=[file_input, threshold_csv],
370
- outputs=file_output
371
- )
372
-
373
- # Tab 3: Informations
374
- with gr.Tab("ℹ️ À propos"):
375
- gr.Markdown("""
376
- ## 🤖 Informations sur le modèle
377
-
378
- ### **Algorithme**
379
- - **Régression Logistique** avec régularisation
380
- - **Vectorisation TF-IDF** (1-gram et 2-grams)
381
- - **Équilibrage SMOTE** pour gérer le déséquilibre des classes
382
- - **5000 features** maximum avec filtrage intelligent
383
-
384
- ### **Performance**
385
- - Entraîné sur dataset SMS/emails réels
386
- - Validation croisée 5-fold
387
- - Métriques: Accuracy, F1-score, AUC-ROC
388
- - Gestion de l'overfitting
389
-
390
- ### **Preprocessing intelligent**
391
- - **Spam**: Conservation ponctuations importantes (!+>)
392
- - **Ham**: Nettoyage standard
393
- - Suppression URLs, emails, téléphones
394
- - Stemming + suppression stopwords anglais
395
-
396
- ### **Classes**
397
- - 🟢 **Ham**: Messages légitimes (conversations, notifications...)
398
- - 🔴 **Spam**: Messages indésirables (pub, arnaques, phishing...)
399
-
400
- ### **Utilisation du seuil**
401
- - **0.1-0.3**: Très sensible (capture plus de spams, plus de faux positifs)
402
- - **0.4**: Équilibré (recommandé)
403
- - **0.5-0.7**: Conservateur (moins de faux positifs)
404
- - **0.8-0.9**: Très conservateur (risque de manquer des spams)
405
-
406
- ### **Conseils**
407
- - Messages courts: classification plus difficile
408
- - Langues: optimisé pour français/anglais
409
- - Fautes d'orthographe: peuvent affecter la précision
410
- - Emojis: traités comme ponctuation
411
-
412
- ---
413
- *Développé avec scikit-learn, NLTK et Gradio*
414
- """)
415
-
416
- return demo
417
-
418
- # =============================================================================
419
- # LANCEMENT DE L'APPLICATION
420
- # =============================================================================
421
-
422
- if __name__ == "__main__":
423
- # Créer et lancer l'interface
424
- demo = create_interface()
425
-
426
- # Afficher l'état des modèles au démarrage
427
- if MODEL and VECTORIZER:
428
- print("✅ Application prête! Modèles chargés avec succès.")
429
  else:
430
- print("⚠️ Application en mode dégradé. Vérifiez les fichiers .pkl")
431
-
432
- demo.launch(
433
- share=False,
434
- inbrowser=True,
435
- show_error=True
436
- )
 
 
 
 
 
 
1
  import gradio as gr
2
+ from transformers import pipeline
 
 
 
 
 
 
 
3
 
4
+ # Charger le modèle existant depuis Hugging Face
5
+ classifier = pipeline("text-classification", model="IreNkweke/HamOrSpamModel")
 
 
 
6
 
7
+ def predict_spam(text):
8
+ result = classifier(text)[0]
9
+ label = result['label'] # 'LABEL_0' ou 'LABEL_1'
10
+ if label in ['LABEL_0', 'Ham']:
11
+ return "Ham (Not Spam)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  else:
13
+ return "Spam"
14
+
15
+ # Interface Gradio
16
+ iface = gr.Interface(
17
+ fn=predict_spam,
18
+ inputs=gr.Textbox(lines=4, placeholder="Enter your message here..."),
19
+ outputs="text",
20
+ title="Spam/Ham Classifier",
21
+ description="Classifier messages as Spam or Ham using a pre-trained model."
22
+ )
23
+
24
+ iface.launch()