Comment créer un bot d'analyse des sentiments des e-mails : un didacticiel PNL
Publié: 2022-03-11Les technologies de traitement du langage naturel sont devenues assez sophistiquées au cours des dernières années. Des géants de la technologie aux amateurs, beaucoup se précipitent pour créer des interfaces riches capables d'analyser, de comprendre et de répondre au langage naturel. Alexa d'Amazon, Cortana de Microsoft, Google Home de Google et Siri d'Apple visent tous à changer la façon dont nous interagissons avec les ordinateurs.
L'analyse des sentiments, un sous-domaine du traitement du langage naturel, consiste en des techniques qui déterminent le ton d'un texte ou d'un discours. Aujourd'hui, grâce à l'apprentissage automatique et aux grandes quantités de données récoltées sur les réseaux sociaux et les sites d'évaluation, nous pouvons former des modèles pour identifier le sentiment d'un passage en langage naturel avec une précision raisonnable.
Dans ce didacticiel, vous apprendrez comment créer un bot capable d'analyser le sentiment des e-mails qu'il reçoit et de vous informer des e-mails qui peuvent nécessiter votre attention immédiatement.
Analyser le sentiment dans les e-mails
Le bot sera construit en utilisant un mélange de développement Java et Python. Les deux processus communiqueront entre eux à l'aide de Thrift. Si vous n'êtes pas familier avec l'une de ces langues ou les deux, vous pouvez continuer à lire car les concepts fondamentaux de cet article s'appliqueront également à d'autres langues.
Pour déterminer si un e-mail nécessite votre attention, le bot l'analysera et déterminera s'il y a une forte tonalité négative. Il enverra ensuite une alerte SMS si nécessaire.
Nous utiliserons Sendgrid pour nous connecter à notre boîte aux lettres et Twilio pour envoyer des alertes SMS.
Analyse des sentiments : un problème d'une simplicité trompeuse
Il y a des mots que nous associons à des émotions positives, comme l'amour, la joie et le plaisir. Et, il y a des mots que nous associons à des émotions négatives, comme la haine, la tristesse et la douleur. Pourquoi ne pas entraîner le modèle à reconnaître ces mots et à compter la fréquence et la force relatives de chaque mot positif et négatif ?
Eh bien, il y a quelques problèmes avec ça.
Il y a d'abord un problème de négation. Par exemple, une phrase comme "La pêche n'est pas mauvaise" implique une émotion positive en utilisant un mot que nous associons le plus souvent à être négatif. Un simple modèle de sac de mots ne pourra pas reconnaître la négation dans cette phrase.
De plus, les sentiments mitigés s'avèrent être un autre problème avec l'analyse des sentiments naïfs. Par exemple, une phrase comme "La pêche n'est pas mauvaise, mais la pomme est vraiment terrible" contient des sentiments mixtes d'intensités mixtes qui interagissent les uns avec les autres. Une approche simple ne pourra pas résoudre les sentiments combinés, l'intensité différente ou les interactions entre les sentiments.
Analyse des sentiments à l'aide d'un réseau de tenseurs neuronaux récursifs
La bibliothèque de traitement du langage naturel de Stanford pour l'analyse des sentiments résout ces problèmes à l'aide d'un réseau de tenseurs neuronaux récursifs (RNTN).
L'algorithme RNTN divise d'abord une phrase en mots individuels. Il construit ensuite un réseau de neurones où les nœuds sont les mots individuels. Enfin, une couche de tenseur est ajoutée afin que le modèle puisse s'ajuster correctement aux interactions entre les mots et les phrases.
Vous pouvez trouver une démonstration visuelle de l'algorithme sur leur site officiel.
Le groupe Stanford NLP a formé le réseau de tenseurs neuronaux récursifs à l'aide de critiques de films IMDB étiquetées manuellement et a découvert que leur modèle était capable de prédire les sentiments avec une très bonne précision.
Bot qui reçoit des e-mails
La première chose à faire est de configurer l'intégration des e-mails afin que les données puissent être transmises à votre bot.
Il existe de nombreuses façons d'y parvenir, mais par souci de simplicité, configurons un serveur Web simple et utilisons le crochet d'analyse entrant de Sendgrid pour diriger les e-mails vers le serveur. Nous pouvons transférer des e-mails vers l'adresse d'analyse entrante de Sendgrid. Sendgrid enverra alors une requête POST à notre serveur Web, et nous pourrons alors traiter les données via notre serveur.
Pour construire le serveur, nous utiliserons Flask, un framework Web simple pour Python.
En plus de construire le serveur Web, nous voudrons connecter le service Web à un domaine. Par souci de brièveté, nous sauterons d'écrire à ce sujet dans l'article. Cependant, vous pouvez en savoir plus ici.
Construire un serveur Web dans Flask est incroyablement simple.
Créez simplement un app.py
et ajoutez ceci au fichier :
from flask import Flask, request import datetime app = Flask(__name__) @app.route('/analyze', methods=['POST']) def analyze(): with open('logfile.txt', 'a') as fp_log: fp_log.write('endpoint hit %s \n' % datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) return "Got it" app.run(host='0.0.0.0')
Si nous déployons cette application derrière un nom de domaine et atteignons le point de terminaison "/analyze", vous devriez voir quelque chose comme ceci :
> >> requests.post('http://sentiments.shanglunwang.com:5000/analyze').text 'Got it'
Ensuite, nous voulons envoyer des e-mails à ce point de terminaison.
Vous pouvez trouver plus de documentation ici, mais vous souhaitez essentiellement configurer Sendgrid pour qu'il soit votre processeur de messagerie et que Sendgrid transfère les e-mails à notre serveur Web.
Voici ma configuration sur Sendgrid. Cela transmettra les e-mails à @sentibot.shanglunwang.com
en tant que requêtes POST à "http://sentiments.shanglunwang.com/analyze":
Vous pouvez utiliser tout autre service prenant en charge l'envoi d'e-mails entrants via des webhooks.
Après avoir tout configuré, essayez d'envoyer un e-mail à votre adresse Sendgrid, vous devriez voir quelque chose comme ceci dans les journaux :
endpoint hit 2017-05-25 14:35:46
C'est génial! Vous avez maintenant un bot capable de recevoir des e-mails. C'est la moitié de ce que nous essayons de faire.
Maintenant, vous voulez donner à ce bot la possibilité d'analyser les sentiments dans les e-mails.
Analyse des sentiments des e-mails avec Stanford NLP
Puisque la bibliothèque Stanford NLP est écrite en Java, nous voudrons construire le moteur d'analyse en Java.
Commençons par télécharger la bibliothèque et les modèles Stanford NLP dans Maven. Créez un nouveau projet Java, ajoutez les éléments suivants à vos dépendances Maven et importez :
<dependency> <groupId>edu.stanford.nlp</groupId> <artifactId>stanford-corenlp</artifactId> <version>3.6.0</version> </dependency>
Le moteur d'analyse des sentiments de Stanford NLP est accessible en spécifiant l'annotateur de sentiment dans le code d'initialisation du pipeline. L'annotation peut ensuite être récupérée sous forme d'arborescence.
Pour les besoins de ce didacticiel, nous voulons simplement connaître le sentiment général d'une phrase, nous n'aurons donc pas besoin d'analyser l'arbre. Nous avons juste besoin de regarder le nœud de base.
Cela rend le code principal relativement simple :
package seanwang; import edu.stanford.nlp.pipeline.*; import edu.stanford.nlp.util.CoreMap; import edu.stanford.nlp.ling.CoreAnnotations; import edu.stanford.nlp.sentiment.SentimentCoreAnnotations; import java.util.*; public class App { public static void main( String[] args ) { Properties pipelineProps = new Properties(); Properties tokenizerProps = new Properties(); pipelineProps.setProperty("annotators", "parse, sentiment"); pipelineProps.setProperty("parse.binaryTrees", "true"); pipelineProps.setProperty("enforceRequirements", "false"); tokenizerProps.setProperty("annotators", "tokenize ssplit"); StanfordCoreNLP tokenizer = new StanfordCoreNLP(tokenizerProps); StanfordCoreNLP pipeline = new StanfordCoreNLP(pipelineProps); String line = "Amazingly grateful beautiful friends are fulfilling an incredibly joyful accomplishment. What an truly terrible idea."; Annotation annotation = tokenizer.process(line); pipeline.annotate(annotation); // normal output for (CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class)) { String output = sentence.get(SentimentCoreAnnotations.SentimentClass.class); System.out.println(output); } } }
Essayez quelques phrases et vous devriez voir les annotations appropriées. Exécution des sorties de l'exemple de code :
Very Positive Negative
Intégration du bot et du moteur d'analyse
Nous avons donc un programme d'analyse de sentiments écrit en Java et un bot de messagerie écrit en Python. Comment fait-on pour qu'ils se parlent ?
Il existe de nombreuses solutions possibles à ce problème, mais ici nous utiliserons Thrift. Nous ferons tourner Sentiment Analyzer en tant que serveur Thrift et le bot de messagerie en tant que client Thrift.
Thrift est un générateur de code et un protocole utilisé pour permettre à deux applications, souvent écrites dans des langages différents, de pouvoir communiquer entre elles en utilisant un protocole défini. Les équipes polyglottes utilisent Thrift pour créer des réseaux de microservices afin de tirer le meilleur parti de chaque langage qu'ils utilisent.
Pour utiliser Thrift, nous aurons besoin de deux choses : un fichier .thrift
pour définir les points de terminaison du service et du code généré pour utiliser le protocole défini dans le fichier .proto
. Pour le service d'analyseur, le sentiment.thrift
ressemble à ceci :

namespace java sentiment namespace py sentiment service SentimentAnalysisService { string sentimentAnalyze(1:string sentence), }
Nous pouvons générer du code client et serveur à l'aide de ce fichier .thrift. Cours:
thrift-0.10.0.exe --gen py sentiment.thrift thrift-0.10.0.exe --gen java sentiment.thrift
Remarque : J'ai généré le code sur une machine Windows. Vous voudrez utiliser le chemin d'accès approprié à l'exécutable Thrift dans votre environnement.
Apportons maintenant les modifications appropriées au moteur d'analyse pour créer un serveur. Votre programme Java devrait ressembler à ceci :
SentimentHandler.java
package seanwang; public class SentimentHandler implements SentimentAnalysisService.Iface { SentimentAnalyzer analyzer; SentimentHandler() { analyzer = new SentimentAnalyzer(); } public String sentimentAnalyze(String sentence) { System.out.println("got: " + sentence); return analyzer.analyze(sentence); } }
Ce gestionnaire est l'endroit où nous recevons la demande d'analyse via le protocole Thrift.
SentimentAnalyzer.java
package seanwang; // ... public class SentimentAnalyzer { StanfordCoreNLP tokenizer; StanfordCoreNLP pipeline; public SentimentAnalyzer() { Properties pipelineProps = new Properties(); Properties tokenizerProps = new Properties(); pipelineProps.setProperty("annotators", "parse, sentiment"); pipelineProps.setProperty("parse.binaryTrees", "true"); pipelineProps.setProperty("enforceRequirements", "false"); tokenizerProps.setProperty("annotators", "tokenize ssplit"); tokenizer = new StanfordCoreNLP(tokenizerProps); pipeline = new StanfordCoreNLP(pipelineProps); } public String analyze(String line) { Annotation annotation = tokenizer.process(line); pipeline.annotate(annotation); String output = ""; for (CoreMap sentence : annotation.get(CoreAnnotations.SentencesAnnotation.class)) { output += sentence.get(SentimentCoreAnnotations.SentimentClass.class); output += "\n"; } return output; } }
L'analyseur utilise la bibliothèque Stanford NLP pour déterminer le sentiment du texte et produit une chaîne contenant les annotations de sentiment pour chaque phrase du texte.
SentimentServer.java
package seanwang; // ... public class SentimentServer { public static SentimentHandler handler; public static SentimentAnalysisService.Processor processor; public static void main(String [] args) { try { handler = new SentimentHandler(); processor = new SentimentAnalysisService.Processor(handler); Runnable simple = new Runnable() { public void run() { simple(processor); } }; new Thread(simple).start(); } catch (Exception x) { x.printStackTrace(); } } public static void simple(SentimentAnalysisService.Processor processor) { try { TServerTransport serverTransport = new TServerSocket(9090); TServer server = new TSimpleServer(new Args(serverTransport).processor(processor)); System.out.println("Starting the simple server..."); server.serve(); } catch (Exception e) { e.printStackTrace(); } } }
Notez que je n'ai pas inclus le fichier SentimentAnalysisService.java
ici puisqu'il s'agit d'un fichier généré. Vous voudrez mettre le code généré dans un endroit où le reste de votre code pourra y accéder.
Maintenant que le serveur est opérationnel, écrivons un client Python pour utiliser le serveur.
client.py
from sentiment import SentimentAnalysisService from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol class SentimentClient: def __init__(self, server='localhost', socket=9090): transport = TSocket.TSocket(server, socket) transport = TTransport.TBufferedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(transport) self.transport = transport self.client = SentimentAnalysisService.Client(protocol) self.transport.open() def __del__(self): self.transport.close() def analyze(self, sentence): return self.client.sentimentAnalyze(sentence) if __name__ == '__main__': client = SentimentClient() print(client.analyze('An amazingly wonderful sentence'))
Exécutez ceci et vous devriez voir :
Very Positive
Génial! Maintenant que le serveur est en cours d'exécution et qu'il communique avec le client, intégrons-le au bot de messagerie en instanciant un client et en y transférant l'e-mail.
import client # ... @app.route('/analyze', methods=['POST']) def analyze(): sentiment_client = client.SentimentClient() with open('logfile.txt', 'a') as fp_log: fp_log.write(str(request.form.get('text'))) fp_log.write(request.form.get('text')) fp_log.write(sentiment_client.analyze(request.form.get('text'))) return "Got it"
Déployez maintenant votre service Java sur la même machine sur laquelle vous exécutez le serveur Web, démarrez le service et redémarrez l'application. Envoyez un e-mail au bot avec une phrase de test et vous devriez voir quelque chose comme ceci dans le fichier journal :
Amazingly wonderfully positive and beautiful sentence. Very Positive
Analyser le courrier électronique
D'accord! Nous avons maintenant un bot de messagerie capable d'effectuer une analyse des sentiments ! Nous pouvons envoyer un e-mail et recevoir une étiquette de sentiment pour chaque phrase que nous avons envoyée. Voyons maintenant comment nous pouvons rendre l'intelligence exploitable.
Pour faire simple, concentrons-nous sur les emails où il y a une forte concentration de phrases négatives et très négatives. Utilisons un système de notation simple et disons que si un e-mail contient plus de 75 % de phrases de sentiments négatifs, nous le marquerons comme un e-mail d'alarme potentiel pouvant nécessiter une réponse immédiate. Implémentons la logique de notation dans la route d'analyse :
@app.route('/analyze', methods=['POST']) def analyze(): text = str(request.form.get('text')) sentiment_client = client.SentimentClient() text.replace('\n', '') # remove all new lines sentences = text.rstrip('.').split('.') # remove the last period before splitting negative_sentences = [ sentence for sentence in sentences if sentiment_client.analyze(sentence).rstrip() in ['Negative', 'Very negative'] # remove newline char ] urgent = len(negative_sentences) / len(sentences) > 0.75 with open('logfile.txt', 'a') as fp_log: fp_log.write("Received: %s" % (request.form.get('text'))) fp_log.write("urgent = %s" % (str(urgent))) return "Got it"
Le code ci-dessus fait quelques hypothèses mais fonctionnera à des fins de démonstration. Envoyez quelques e-mails à votre bot et vous devriez voir l'analyse des e-mails dans les journaux :
Received: Here is a test for the system. This is supposed to be a non-urgent request. It's very good! For the most part this is positive or neutral. Great things are happening! urgent = False Received: This is an urgent request. Everything is truly awful. This is a disaster. People hate this tasteless mail. urgent = True
Envoi d'une alerte
Nous avons presque terminé !
Nous avons construit un bot de messagerie capable de recevoir des e-mails, d'effectuer une analyse des sentiments et de déterminer si un e-mail nécessite une attention immédiate. Désormais, il suffit d'envoyer une alerte SMS lorsqu'un e-mail est particulièrement négatif.
Nous utiliserons Twilio pour envoyer une alerte SMS. Leur API Python, qui est documentée ici, est assez simple. Modifions la route d'analyse pour envoyer une requête lorsqu'elle reçoit une requête urgente.
def send_message(body): twilio_client.messages.create( to=on_call, from_=os.getenv('TWILIO_PHONE_NUMBER'), body=body ) app = Flask(__name__) @app.route('/analyze', methods=['POST']) def analyze(): text = str(request.form.get('text')) sentiment_client = client.SentimentClient() text.replace('\n', '') # remove all new lines sentences = text.rstrip('.').split('.') # remove the last period before splitting negative_sentences = [ sentence for sentence in sentences if sentiment_client.analyze(sentence).rstrip() in ['Negative', 'Very negative'] # remove newline char ] urgent = len(negative_sentences) / len(sentences) > 0.75 if urgent: send_message('Highly negative email received. Please take action') with open('logfile.txt', 'a') as fp_log: fp_log.write("Received: " % request.form.get('text')) fp_log.write("urgent = %s" % (str(urgent))) fp_log.write("\n") return "Got it"
Vous devrez définir vos variables d'environnement sur les informations d'identification de votre compte Twilio et définir le numéro de garde sur un téléphone que vous pouvez vérifier. Une fois que vous avez fait cela, envoyez un e-mail au point de terminaison d'analyse et vous devriez voir un texte envoyé au numéro de téléphone en question.
Et nous avons terminé !
Le traitement du langage naturel simplifié avec Stanford NLP
Dans cet article, vous avez appris à créer un bot d'analyse des sentiments par e-mail à l'aide de la bibliothèque Stanford NLP. La bibliothèque aide à résumer tous les détails du traitement du langage naturel et vous permet de l'utiliser comme élément de base pour vos applications NLP.
J'espère que cet article a démontré l'une des nombreuses applications potentielles étonnantes de l'analyse des sentiments, et que cela vous inspire à créer votre propre application NLP.
Vous pouvez trouver le code du bot d'analyse des sentiments par e-mail à partir de ce didacticiel NLP sur GitHub.