Added prediction probabilities on error reports + added unit tests (not finished yet)
This commit is contained in:
parent
89997585c6
commit
6416bcd075
9 changed files with 258 additions and 60 deletions
Binary file not shown.
|
|
@ -53,7 +53,7 @@ if st.session_state.prediction_result:
|
||||||
sentiment = st.session_state.prediction_result["sentiment"].capitalize()
|
sentiment = st.session_state.prediction_result["sentiment"].capitalize()
|
||||||
prob = st.session_state.prediction_result["probability"]
|
prob = st.session_state.prediction_result["probability"]
|
||||||
st.success(f"Sentiment : {sentiment}")
|
st.success(f"Sentiment : {sentiment}")
|
||||||
st.info(f"Probabilité : {prob:.2f}")
|
st.info(f"Probabilité que le tweet soit positif: {prob:.2f}")
|
||||||
|
|
||||||
# Gestion du bouton signalement
|
# Gestion du bouton signalement
|
||||||
if st.session_state.show_report_button and not st.session_state.report_sent:
|
if st.session_state.show_report_button and not st.session_state.report_sent:
|
||||||
|
|
@ -61,15 +61,19 @@ if st.session_state.show_report_button and not st.session_state.report_sent:
|
||||||
try:
|
try:
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
"http://localhost:8000/report_error",
|
"http://localhost:8000/report_error",
|
||||||
json={"tweet": tweet, "prediction": sentiment}
|
json={
|
||||||
|
"tweet": tweet,
|
||||||
|
"prediction": sentiment,
|
||||||
|
"probability": st.session_state.prediction_result["probability"] # Transmettre la probabilité
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
# Mettre à jour les états
|
# Mettre à jour les états
|
||||||
st.session_state.show_report_button = False
|
st.session_state.show_report_button = False
|
||||||
st.session_state.report_sent = True
|
st.session_state.report_sent = True
|
||||||
st.session_state.last_report_sent = data.get("report_sent", False)
|
st.session_state.last_report_sent = data.get("report_sent", False)
|
||||||
|
|
||||||
# Forcer un re-run
|
# Forcer un re-run
|
||||||
st.rerun()
|
st.rerun()
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,20 @@ from mlflow.tracking import MlflowClient
|
||||||
from tensorflow.keras.models import load_model
|
from tensorflow.keras.models import load_model
|
||||||
from tensorflow.keras.preprocessing.sequence import pad_sequences
|
from tensorflow.keras.preprocessing.sequence import pad_sequences
|
||||||
|
|
||||||
# 🔁 Import de la fonction de prétraitement depuis ../../functions.py
|
# A DECOMMENTER POUR DEVELOPPER. AUTREMENT, LAISSER AINSI
|
||||||
|
# Accéder à .env
|
||||||
PARENT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
|
PARENT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
|
||||||
sys.path.append(PARENT_DIR)
|
sys.path.append(PARENT_DIR)
|
||||||
from functions import preprocess_tweet
|
# 🔐 Charger les variables d'environnement (.env à deux niveaux au-dessus)
|
||||||
|
load_dotenv(dotenv_path=os.path.join(PARENT_DIR, ".env"))
|
||||||
|
|
||||||
|
|
||||||
|
# 🔁 Import de la fonction de prétraitement (LOCAL)
|
||||||
|
from preprocessing import preprocess_tweet
|
||||||
|
|
||||||
# 📧 Import du service email
|
# 📧 Import du service email
|
||||||
from email_service import send_error_report_email
|
from email_service import send_error_report_email
|
||||||
|
|
||||||
# 🔐 Charger les variables d'environnement (.env à deux niveaux au-dessus)
|
|
||||||
load_dotenv(dotenv_path=os.path.join(PARENT_DIR, ".env"))
|
|
||||||
|
|
||||||
# 🔗 Configurer MLflow
|
# 🔗 Configurer MLflow
|
||||||
mlflow_tracking_uri = os.getenv("MLFLOW_TRACKING_URI")
|
mlflow_tracking_uri = os.getenv("MLFLOW_TRACKING_URI")
|
||||||
|
|
@ -38,6 +42,7 @@ class TweetRequest(BaseModel):
|
||||||
class ReportRequest(BaseModel):
|
class ReportRequest(BaseModel):
|
||||||
tweet: str
|
tweet: str
|
||||||
prediction: str
|
prediction: str
|
||||||
|
probability: float
|
||||||
|
|
||||||
# 🧠 Stockage des signalements d'erreurs
|
# 🧠 Stockage des signalements d'erreurs
|
||||||
error_reports = {}
|
error_reports = {}
|
||||||
|
|
@ -58,6 +63,7 @@ def load_model_and_artifacts(model_name=MODEL_NAME, stage=STAGE):
|
||||||
|
|
||||||
# Extraire le tag d'embedding
|
# Extraire le tag d'embedding
|
||||||
model_version_info = client.get_model_version(model_name, version_info.version)
|
model_version_info = client.get_model_version(model_name, version_info.version)
|
||||||
|
# glove est ici la valeur par défaut si embedding_type n'est pas trouvé.
|
||||||
embedding_type = model_version_info.tags.get("embedding_type", "glove").lower()
|
embedding_type = model_version_info.tags.get("embedding_type", "glove").lower()
|
||||||
|
|
||||||
# Déterminer les chemins des artefacts
|
# Déterminer les chemins des artefacts
|
||||||
|
|
@ -73,6 +79,8 @@ def load_model_and_artifacts(model_name=MODEL_NAME, stage=STAGE):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Embedding type inconnu : {embedding_type}")
|
raise ValueError(f"Embedding type inconnu : {embedding_type}")
|
||||||
|
|
||||||
|
print(f"Modèle {embedding_type} trouvé. Téléchargement du modèle lié au run_id suivant : {run_id}")
|
||||||
|
|
||||||
def dl(path):
|
def dl(path):
|
||||||
return client.download_artifacts(run_id=run_id, path=f"{base_path}/{path}", dst_path=local_dir)
|
return client.download_artifacts(run_id=run_id, path=f"{base_path}/{path}", dst_path=local_dir)
|
||||||
|
|
||||||
|
|
@ -117,7 +125,11 @@ def predict_sentiment(request: TweetRequest):
|
||||||
sequence = tokenizer.texts_to_sequences([processed_tweet])
|
sequence = tokenizer.texts_to_sequences([processed_tweet])
|
||||||
sequence_padded = pad_sequences(sequence, maxlen=model.input_shape[1])
|
sequence_padded = pad_sequences(sequence, maxlen=model.input_shape[1])
|
||||||
prediction_prob = model.predict(sequence_padded)[0][0]
|
prediction_prob = model.predict(sequence_padded)[0][0]
|
||||||
sentiment = "positif" if prediction_prob >= 0.5 else "negatif"
|
if prediction_prob >=0.5:
|
||||||
|
sentiment = "positif"
|
||||||
|
else:
|
||||||
|
sentiment = "negatif"
|
||||||
|
# prediction_prob = 1-prediction_prob
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"Erreur d'inférence : {e}")
|
raise HTTPException(status_code=500, detail=f"Erreur d'inférence : {e}")
|
||||||
|
|
||||||
|
|
@ -126,35 +138,65 @@ def predict_sentiment(request: TweetRequest):
|
||||||
"probability": float(prediction_prob)
|
"probability": float(prediction_prob)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# @app.post("/report_error")
|
||||||
|
# def report_error(request: ReportRequest):
|
||||||
|
# tweet = request.tweet.strip()
|
||||||
|
# prediction = request.prediction.strip().lower()
|
||||||
|
# probability = request.probability
|
||||||
|
|
||||||
|
# if not tweet or not prediction:
|
||||||
|
# raise HTTPException(status_code=400, detail="Tweet ou prédiction manquants.")
|
||||||
|
# if probability < 0 or probability > 1:
|
||||||
|
# raise HTTPException(status_code=400, detail="Probabilité invalide. Elle doit être entre 0 et 1.")
|
||||||
|
|
||||||
|
# # Ajouter ou mettre à jour le signalement du tweet avec la probabilité
|
||||||
|
# error_reports[tweet] = prediction + ' (p = ' + str(probability) + ') '
|
||||||
|
|
||||||
|
# # ✅ Envoi de l'email sans attendre un multiple de 3
|
||||||
|
# try:
|
||||||
|
# email_success = send_error_report_email(error_reports.copy())
|
||||||
|
# if email_success:
|
||||||
|
# print(f"✅ Email envoyé avec succès pour {len(error_reports)} signalements")
|
||||||
|
# report_sent = True
|
||||||
|
# else:
|
||||||
|
# print(f"❌ Échec de l'envoi de l'email")
|
||||||
|
# report_sent = False
|
||||||
|
# except Exception as e:
|
||||||
|
# print(f"❌ Erreur lors de l'envoi de l'email : {e}")
|
||||||
|
# report_sent = False
|
||||||
|
|
||||||
|
# return {"report_sent": report_sent}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/report_error")
|
@app.post("/report_error")
|
||||||
def report_error(request: ReportRequest):
|
def report_error(request: ReportRequest):
|
||||||
tweet = request.tweet.strip()
|
tweet = request.tweet.strip()
|
||||||
prediction = request.prediction.strip().lower()
|
prediction = request.prediction.strip().lower()
|
||||||
|
probability = request.probability
|
||||||
|
|
||||||
if not tweet or not prediction:
|
if not tweet or not prediction:
|
||||||
raise HTTPException(status_code=400, detail="Tweet ou prédiction manquants.")
|
raise HTTPException(status_code=400, detail="Tweet ou prédiction manquants.")
|
||||||
|
if probability < 0 or probability > 1:
|
||||||
|
raise HTTPException(status_code=400, detail="Probabilité invalide. Elle doit être entre 0 et 1.")
|
||||||
|
|
||||||
# Ajouter ou mettre à jour le signalement du tweet
|
# Ajouter ou mettre à jour le signalement du tweet avec la probabilité
|
||||||
error_reports[tweet] = prediction
|
error_reports[tweet] = prediction + f' (p = {probability:.2f} ) '
|
||||||
|
|
||||||
report_sent = False
|
report_sent = False
|
||||||
|
|
||||||
# Condition : à chaque multiple de 3 signalements totaux
|
# Condition : À chaque multiple de 3 signalements, un mail est envoyé
|
||||||
if len(error_reports) % 3 == 0:
|
try:
|
||||||
report_sent = True
|
if len(error_reports) % 3 == 0: # La condition reste
|
||||||
|
report_sent = True
|
||||||
# 📧 NOUVEAU : Envoyer l'email de rapport
|
|
||||||
try:
|
|
||||||
print(f"📧 Tentative d'envoi d'email pour {len(error_reports)} signalements...")
|
print(f"📧 Tentative d'envoi d'email pour {len(error_reports)} signalements...")
|
||||||
email_success = send_error_report_email(error_reports.copy())
|
email_success = send_error_report_email(error_reports.copy())
|
||||||
|
|
||||||
if email_success:
|
if email_success:
|
||||||
print(f"✅ Email envoyé avec succès pour {len(error_reports)} signalements")
|
print(f"✅ Email envoyé avec succès pour {len(error_reports)} signalements")
|
||||||
else:
|
else:
|
||||||
print(f"❌ Échec de l'envoi de l'email pour {len(error_reports)} signalements")
|
print(f"❌ Échec de l'envoi de l'email pour {len(error_reports)} signalements")
|
||||||
|
except Exception as e:
|
||||||
except Exception as e:
|
print(f"❌ Erreur lors de l'envoi de l'email : {e}")
|
||||||
print(f"❌ Erreur lors de l'envoi de l'email : {e}")
|
# On continue même si l'email échoue pour ne pas bloquer l'API
|
||||||
# On continue même si l'email échoue pour ne pas bloquer l'API
|
|
||||||
|
|
||||||
return {"report_sent": report_sent}
|
return {"report_sent": report_sent}
|
||||||
44
deployment/api/preprocessing.py
Normal file
44
deployment/api/preprocessing.py
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import re
|
||||||
|
import html
|
||||||
|
import nltk
|
||||||
|
from nltk.corpus import stopwords
|
||||||
|
from nltk.tokenize import word_tokenize
|
||||||
|
from nltk.stem import WordNetLemmatizer
|
||||||
|
|
||||||
|
# Assurer que les ressources nécessaires sont disponibles
|
||||||
|
try:
|
||||||
|
stopwords.words('english')
|
||||||
|
word_tokenize("test")
|
||||||
|
WordNetLemmatizer().lemmatize("testing")
|
||||||
|
except LookupError:
|
||||||
|
nltk.download('punkt')
|
||||||
|
nltk.download('punkt_tab')
|
||||||
|
nltk.download('stopwords')
|
||||||
|
nltk.download('wordnet')
|
||||||
|
nltk.download('omw-1.4')
|
||||||
|
|
||||||
|
def preprocess_tweet(tweet):
|
||||||
|
"""
|
||||||
|
Fonction de prétraitement des tweets pour l'API de sentiment analysis
|
||||||
|
"""
|
||||||
|
if not isinstance(tweet, str):
|
||||||
|
return ""
|
||||||
|
tweet = html.unescape(tweet)
|
||||||
|
tweet = tweet.lower()
|
||||||
|
tweet = re.sub(r'https?://\S+|www\.\S+', '<URL>', tweet)
|
||||||
|
tweet = re.sub(r'@\w+', '<MENTION>', tweet)
|
||||||
|
tweet = re.sub(r'#(\w+)', r'# \1', tweet)
|
||||||
|
tweet = re.sub(r'[^\w\s<>@#!?]', '', tweet)
|
||||||
|
|
||||||
|
tokens = word_tokenize(tweet)
|
||||||
|
|
||||||
|
lemmatizer = WordNetLemmatizer()
|
||||||
|
tokens = [lemmatizer.lemmatize(token) for token in tokens]
|
||||||
|
|
||||||
|
stop_words = set(stopwords.words('english'))
|
||||||
|
important_words = {'no', 'not', 'nor', 'neither', 'never', 'nobody', 'none', 'nothing', 'nowhere'}
|
||||||
|
stop_words = stop_words - important_words
|
||||||
|
|
||||||
|
tokens = [token for token in tokens if token not in stop_words]
|
||||||
|
|
||||||
|
return ' '.join(tokens)
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Created on Sat Jul 5 15:03:24 2025
|
|
||||||
|
|
||||||
@author: madfuckinman
|
|
||||||
"""
|
|
||||||
|
|
||||||
# test_alias_email.py
|
|
||||||
import os
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
from email_service import send_error_report_email
|
|
||||||
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
print("🔧 Configuration Email:")
|
|
||||||
print(f"Serveur SMTP: {os.getenv('SMTP_SERVER')}")
|
|
||||||
print(f"Authentification: {os.getenv('SMTP_EMAIL')}")
|
|
||||||
print(f"Expéditeur (alias): {os.getenv('SMTP_FROM_ALIAS')}")
|
|
||||||
print(f"Destinataire: {os.getenv('ADMIN_EMAIL')}")
|
|
||||||
|
|
||||||
# Test
|
|
||||||
test_reports = {
|
|
||||||
"Service client décevant": "positif",
|
|
||||||
"J'adore cette compagnie": "negatif",
|
|
||||||
"Vol annulé sans prévenir": "positif"
|
|
||||||
}
|
|
||||||
|
|
||||||
print("\n📧 Test d'envoi depuis l'alias...")
|
|
||||||
result = send_error_report_email(test_reports)
|
|
||||||
print(f"Résultat : {'✅ Succès' if result else '❌ Échec'}")
|
|
||||||
77
deployment/api/tests/test_email_service.py
Normal file
77
deployment/api/tests/test_email_service.py
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Created on Sat Jul 5 15:03:24 2025
|
||||||
|
|
||||||
|
@author: madfuckinman
|
||||||
|
"""
|
||||||
|
|
||||||
|
# # test_alias_email.py
|
||||||
|
# import os
|
||||||
|
# from dotenv import load_dotenv
|
||||||
|
# from email_service import send_error_report_email
|
||||||
|
|
||||||
|
# load_dotenv()
|
||||||
|
|
||||||
|
# print("🔧 Configuration Email:")
|
||||||
|
# print(f"Serveur SMTP: {os.getenv('SMTP_SERVER')}")
|
||||||
|
# print(f"Authentification: {os.getenv('SMTP_EMAIL')}")
|
||||||
|
# print(f"Expéditeur (alias): {os.getenv('SMTP_FROM_ALIAS')}")
|
||||||
|
# print(f"Destinataire: {os.getenv('ADMIN_EMAIL')}")
|
||||||
|
|
||||||
|
# # Test
|
||||||
|
# test_reports = {
|
||||||
|
# "Service client décevant": "positif",
|
||||||
|
# "J'adore cette compagnie": "negatif",
|
||||||
|
# "Vol annulé sans prévenir": "positif"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# print("\n📧 Test d'envoi depuis l'alias...")
|
||||||
|
# result = send_error_report_email(test_reports)
|
||||||
|
# print(f"Résultat : {'✅ Succès' if result else '❌ Échec'}")
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Ajouter le répertoire parent au path pour importer email_service
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../")))
|
||||||
|
|
||||||
|
from email_service import send_error_report_email
|
||||||
|
|
||||||
|
# Charger le fichier .env situé un niveau au-dessus
|
||||||
|
dotenv_path = '../../../.env'
|
||||||
|
load_dotenv(dotenv_path)
|
||||||
|
|
||||||
|
def test_email_service_with_alias():
|
||||||
|
"""
|
||||||
|
Teste l'envoi d'un email avec la fonction send_error_report_email
|
||||||
|
"""
|
||||||
|
# ⚙️ Vérifier si les variables d'environnement nécessaires sont présentes
|
||||||
|
smtp_server = os.getenv("SMTP_SERVER")
|
||||||
|
smtp_email = os.getenv("SMTP_EMAIL")
|
||||||
|
admin_email = os.getenv("ADMIN_EMAIL")
|
||||||
|
|
||||||
|
assert smtp_server, "SMTP_SERVER non défini dans le fichier .env"
|
||||||
|
assert smtp_email, "SMTP_EMAIL non défini dans le fichier .env"
|
||||||
|
assert admin_email, "ADMIN_EMAIL non défini dans le fichier .env"
|
||||||
|
|
||||||
|
# Configuration de test
|
||||||
|
print("🔧 Configuration Email :")
|
||||||
|
print(f"Serveur SMTP : {smtp_server}")
|
||||||
|
print(f"Authentification : {smtp_email}")
|
||||||
|
print(f"Destinataire : {admin_email}")
|
||||||
|
|
||||||
|
# Cas de test
|
||||||
|
test_reports = {
|
||||||
|
"Service client décevant": "positif",
|
||||||
|
"Erreur à l'embarquement": "negatif",
|
||||||
|
"Vol annulé sans prévenir": "positif"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 📧 Tester la fonction d'envoi
|
||||||
|
result = send_error_report_email(test_reports)
|
||||||
|
|
||||||
|
# ✅ Assertion pour vérifier que la fonction fonctionne correctement
|
||||||
|
assert result is True, "L'email n'a pas été envoyé avec succès"
|
||||||
27
deployment/api/tests/test_main.py
Normal file
27
deployment/api/tests/test_main.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import pytest
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
from main import app
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
def test_root_endpoint():
|
||||||
|
response = client.get("/")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"message": "API Sentiment - Air Paradis - en ligne"}
|
||||||
|
|
||||||
|
def test_predict_sentiment():
|
||||||
|
response = client.post("/predict", json={"tweet": "J'adore cette compagnie aérienne !"})
|
||||||
|
assert response.status_code == 200
|
||||||
|
data = response.json()
|
||||||
|
assert "sentiment" in data
|
||||||
|
assert "probability" in data
|
||||||
|
assert data["sentiment"] in ["positif", "negatif"]
|
||||||
|
|
||||||
|
def test_missing_tweet():
|
||||||
|
response = client.post("/predict", json={})
|
||||||
|
assert response.status_code == 422 # Unprocessable Entity (FastAPI)
|
||||||
|
|
||||||
|
def test_empty_tweet():
|
||||||
|
response = client.post("/predict", json={"tweet": ""})
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert response.json()["detail"] == "Tweet vide ou invalide après prétraitement."
|
||||||
36
deployment/api/tests/test_preprocessing.py
Normal file
36
deployment/api/tests/test_preprocessing.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Ajouter le répertoire parent au path pour importer email_service
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../")))
|
||||||
|
from preprocessing import preprocess_tweet
|
||||||
|
|
||||||
|
|
||||||
|
def test_preprocess_tweet_removes_hashtags():
|
||||||
|
tweet = """
|
||||||
|
Just flew w/ @AirParadis 🚀 & I’m in LOVE! Épic service, comfy seats.
|
||||||
|
#bestflight #AirParadis
|
||||||
|
"""
|
||||||
|
assert preprocess_tweet(tweet) == """"
|
||||||
|
aze
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_preprocess_tweet_removes_mentions():
|
||||||
|
tweet = """
|
||||||
|
"Flight of dreams" w/ @AirParadis! Got food, space & smiles 😄 I’ll book again!
|
||||||
|
#AirParadis
|
||||||
|
"""
|
||||||
|
assert preprocess_tweet(tweet) == "merci"
|
||||||
|
|
||||||
|
def test_preprocess_tweet_lowercases_text():
|
||||||
|
tweet = """
|
||||||
|
My 3rd time w/ @AirParadis & still amazed 😍 Crew = lovely à every step!
|
||||||
|
#flyhappy #AirParadis
|
||||||
|
"""
|
||||||
|
assert preprocess_tweet(tweet) == "je suis content"
|
||||||
|
|
||||||
|
tweet = """
|
||||||
|
Just flew w/ @AirParadis 🚀 & I’m in LOVE! Épic service, comfy seats.
|
||||||
|
#bestflight #AirParadis
|
||||||
|
"""
|
||||||
|
preprocess_tweet(tweet)
|
||||||
|
|
@ -39,12 +39,11 @@ def downsample_data(df, n_samples=50000, random_state=42):
|
||||||
def preprocess_tweet(tweet):
|
def preprocess_tweet(tweet):
|
||||||
if not isinstance(tweet, str):
|
if not isinstance(tweet, str):
|
||||||
return ""
|
return ""
|
||||||
|
tweet = html.unescape(tweet)
|
||||||
tweet = tweet.lower()
|
tweet = tweet.lower()
|
||||||
tweet = re.sub(r'https?://\S+|www\.\S+', '<URL>', tweet)
|
tweet = re.sub(r'https?://\S+|www\.\S+', '<URL>', tweet)
|
||||||
tweet = re.sub(r'@\w+', '<MENTION>', tweet)
|
tweet = re.sub(r'@\w+', '<MENTION>', tweet)
|
||||||
tweet = re.sub(r'#(\w+)', r'# \1', tweet)
|
tweet = re.sub(r'#(\w+)', r'# \1', tweet)
|
||||||
tweet = html.unescape(tweet)
|
|
||||||
tweet = re.sub(r'[^\w\s<>@#!?]', '', tweet)
|
tweet = re.sub(r'[^\w\s<>@#!?]', '', tweet)
|
||||||
|
|
||||||
tokens = word_tokenize(tweet)
|
tokens = word_tokenize(tweet)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue