Cum să construiți un bot de analiză a sentimentelor de e-mail: un tutorial NLP

Publicat: 2022-03-11

Tehnologiile de procesare a limbajului natural au devenit destul de sofisticate în ultimii ani. De la giganți ai tehnologiei la pasionați, mulți se grăbesc să construiască interfețe bogate care pot analiza, înțelege și răspunde la limbajul natural. Alexa de la Amazon, Cortana de la Microsoft, Google Home și Siri de la Apple își propun toate să schimbe modul în care interacționăm cu computerele.

Analiza sentimentelor, un subdomeniu al procesării limbajului natural, constă în tehnici care determină tonul unui text sau al unui discurs. Astăzi, cu învățare automată și cantități mari de date colectate de pe rețelele sociale și site-uri de recenzii, putem antrena modele pentru a identifica sentimentul unui pasaj în limbaj natural cu o acuratețe destul de mare.

Tutorial bot de analiză a sentimentelor prin e-mail

În acest tutorial, veți învăța cum puteți crea un bot care poate analiza sentimentul e-mailurilor pe care le primește și să vă anunțe despre e-mailurile care ar putea necesita atenția dvs. imediat.

Analizarea sentimentelor din e-mailuri

Botul va fi construit folosind o combinație de dezvoltare Java și Python. Cele două procese vor comunica între ele folosind Thrift. Dacă nu sunteți familiarizat cu una sau ambele dintre aceste limbi, puteți citi în continuare, deoarece conceptele fundamentale ale acestui articol vor fi valabile și pentru alte limbi.

Pentru a determina dacă un e-mail necesită atenția dvs., bot-ul îl va analiza și va determina dacă există un ton negativ puternic. Va trimite apoi o alertă text dacă este necesar.

Vom folosi Sendgrid pentru a ne conecta la căsuța poștală și Twilio pentru a trimite alerte text.

Analiza sentimentelor: o problemă înșelător de simplă

Există cuvinte pe care le asociem cu emoții pozitive, cum ar fi dragostea, bucuria și plăcerea. Și, există cuvinte pe care le asociem cu emoții negative, cum ar fi ura, tristețea și durerea. De ce să nu antrenați modelul să recunoască aceste cuvinte și să numere frecvența relativă și puterea fiecărui cuvânt pozitiv și negativ?

Ei bine, există câteva probleme cu asta.

În primul rând, există o problemă de negație. De exemplu, o propoziție precum „Piersica nu este rea” implică o emoție pozitivă folosind un cuvânt pe care cel mai adesea îl asociem cu a fi negativ. Un simplu model de pungă de cuvinte nu va putea recunoaște negația din această propoziție.

În plus, sentimentele mixte se dovedesc a fi încă o problemă cu analiza sentimentelor naive. De exemplu, o propoziție precum „Piersica nu este rea, dar mărul este cu adevărat groaznic” conține sentimente amestecate de intensități mixte care interacționează între ele. O abordare simplă nu va putea rezolva sentimentele combinate, intensitatea diferită sau interacțiunile dintre sentimente.

Analiza sentimentelor utilizând rețeaua de tensori neuronali recursivi

Biblioteca de procesare a limbajului natural Stanford pentru analiza sentimentelor rezolvă aceste probleme folosind o rețea de tensor neuronal recursiv (RNTN).

RNTN pe o propoziție

Algoritmul RNTN împarte mai întâi o propoziție în cuvinte individuale. Apoi construiește o rețea neuronală în care nodurile sunt cuvintele individuale. În cele din urmă, se adaugă un strat tensor, astfel încât modelul să se poată ajusta în mod corespunzător pentru interacțiunile dintre cuvinte și fraze.

Puteți găsi o demonstrație vizuală a algoritmului pe site-ul lor oficial.

Grupul Stanford NLP a antrenat Recursive Neural Tensor Network folosind recenzii de filme IMDB etichetate manual și a constatat că modelul lor este capabil să prezică sentimentele cu foarte bună acuratețe.

Bot care primește e-mailuri

Primul lucru pe care doriți să-l faceți este să configurați integrarea e-mailului, astfel încât datele să poată fi transmise către bot.

Există multe modalități de a realiza acest lucru, dar, de dragul simplității, să instalăm un server web simplu și să folosim cârligul de analiză de intrare al Sendgrid pentru a trimite e-mailurile către server. Putem redirecționa e-mailuri către adresa de analiză de intrare a lui Sendgrid. Sendgrid va trimite apoi o solicitare POST către serverul nostru web, iar apoi vom putea procesa datele prin serverul nostru.

Pentru a construi serverul, vom folosi Flask, un cadru web simplu pentru Python.

Pe lângă construirea serverului web, vom dori să conectăm serviciul web la un domeniu. Pentru concizie, vom omite să scriem despre asta în articol. Cu toate acestea, puteți citi mai multe despre el aici.

Construirea unui server web în Flask este incredibil de simplă.

Pur și simplu creați un app.py și adăugați-l în fișier:

 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')

Dacă implementăm această aplicație în spatele unui nume de domeniu și atingem punctul final „/analyze”, ar trebui să vedeți ceva de genul acesta:

 > >> requests.post('http://sentiments.shanglunwang.com:5000/analyze').text 'Got it'

În continuare, dorim să trimitem e-mailuri către acest punct final.

Puteți găsi mai multă documentație aici, dar, în esență, doriți să configurați Sendgrid să fie procesorul dvs. de e-mail și ca Sendgrid să trimită e-mailurile către serverul nostru web.

Iată configurația mea pe Sendgrid. Aceasta va trimite e-mailuri către @sentibot.shanglunwang.com ca solicitări POST către „http://sentiments.shanglunwang.com/analyze”:

Configurare Sendgrid

Puteți utiliza orice alt serviciu care acceptă trimiterea de e-mailuri de intrare prin webhook-uri.

După ce ați configurat totul, încercați să trimiteți un e-mail la adresa dvs. Sendgrid, ar trebui să vedeți ceva de genul acesta în jurnale:

 endpoint hit 2017-05-25 14:35:46

Grozav! Acum aveți un bot care poate primi e-mailuri. Asta este jumătate din ceea ce încercăm să facem.

Acum, doriți să oferiți acestui bot capacitatea de a analiza sentimentele din e-mailuri.

Analiza sentimentelor de e-mail cu Stanford NLP

Deoarece biblioteca Stanford NLP este scrisă în Java, vom dori să construim motorul de analiză în Java.

Să începem prin a descărca biblioteca Stanford NLP și modelele în Maven. Creați un nou proiect Java, adăugați următoarele la dependențele dvs. Maven și importați:

 <dependency> <groupId>edu.stanford.nlp</groupId> <artifactId>stanford-corenlp</artifactId> <version>3.6.0</version> </dependency>

Motorul de analiză a sentimentelor de la Stanford NLP poate fi accesat prin specificarea adnotatorului de sentiment în codul de inițializare a conductei. Adnotarea poate fi apoi preluată ca structură arborescentă.

În scopul acestui tutorial, vrem doar să cunoaștem sentimentul general al unei propoziții, așa că nu va trebui să analizăm arborele. Trebuie doar să ne uităm la nodul de bază.

Acest lucru face ca codul principal să fie relativ simplu:

 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); } } }

Încercați câteva propoziții și ar trebui să vedeți adnotările corespunzătoare. Rularea exemplului de ieșiri de cod:

 Very Positive Negative

Integrarea Bot-ului și a motorului de analiză

Deci avem un program de analiză a sentimentelor scris în Java și un bot de e-mail scris în Python. Cum îi facem să vorbească între ei?

Există multe soluții posibile la această problemă, dar aici vom folosi Thrift. Vom activa Sentiment Analyzer ca server Thrift și botul de e-mail ca client Thrift.

Thrift este un generator de cod și un protocol folosit pentru a permite două aplicații, adesea scrise în limbi diferite, să poată comunica între ele folosind un protocol definit. Echipele Polyglot folosesc Thrift pentru a construi rețele de microservicii pentru a valorifica tot ce este mai bun din fiecare limbă pe care o folosesc.

Pentru a folosi Thrift, vom avea nevoie de două lucruri: un fișier .thrift pentru a defini punctele finale ale serviciului și codul generat pentru a utiliza protocolul definit în fișierul .proto . Pentru serviciul de analiză, sentiment.thrift arată astfel:

 namespace java sentiment namespace py sentiment service SentimentAnalysisService { string sentimentAnalyze(1:string sentence), }

Putem genera cod de client și server folosind acest fișier .thrift. Alerga:

 thrift-0.10.0.exe --gen py sentiment.thrift thrift-0.10.0.exe --gen java sentiment.thrift

Notă: Am generat codul pe o mașină Windows. Veți dori să utilizați calea corespunzătoare către executabilul Thrift în mediul dvs.

Acum, să facem modificările corespunzătoare motorului de analiză pentru a crea un server. Programul dvs. Java ar trebui să arate astfel:

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); } }

Acest handler este locul în care primim cererea de analiză prin protocolul 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; } }

Analizorul folosește biblioteca Stanford NLP pentru a determina sentimentul textului și produce un șir care conține adnotări de sentiment pentru fiecare propoziție din text.

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(); } } }

Rețineți că nu am inclus fișierul SentimentAnalysisService.java aici, deoarece este un fișier generat. Veți dori să puneți codul generat într-un loc unde restul codului dvs. îl poate accesa.

Acum că avem serverul activ, să scriem un client Python pentru a utiliza serverul.

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'))

Rulați asta și ar trebui să vedeți:

 Very Positive

Grozav! Acum că avem serverul care rulează și vorbește cu clientul, haideți să-l integrăm cu botul de e-mail prin instanțierea unui client și introducerea e-mailului în el.

 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"

Acum implementați serviciul Java pe aceeași mașină pe care rulați serverul web, porniți serviciul și reporniți aplicația. Trimiteți un e-mail botului cu o propoziție de test și ar trebui să vedeți ceva de genul acesta în fișierul jurnal:

 Amazingly wonderfully positive and beautiful sentence. Very Positive

Analizând e-mailul

In regula! Acum avem un bot de e-mail care poate efectua analiza sentimentelor! Putem trimite un e-mail și primi o etichetă de sentiment pentru fiecare propoziție pe care am trimis-o. Acum, să explorăm cum putem face ca informațiile să fie acționabile.

Pentru a menține lucrurile simple, să ne concentrăm pe e-mailurile în care există o concentrație mare de propoziții negative și foarte negative. Să folosim un sistem simplu de punctare și să spunem că, dacă un e-mail conține mai mult de 75% propoziții negative, îl vom marca ca un potențial e-mail de alarmă care poate necesita un răspuns imediat. Să implementăm logica de punctare în traseul de analiză:

 @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"

Codul de mai sus face câteva presupuneri, dar va funcționa în scopuri demonstrative. Trimiteți câteva e-mailuri botului dvs. și ar trebui să vedeți analiza e-mailurilor în jurnale:

 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

Trimiterea unei alerte

Aproape am terminat!

Am creat un bot de e-mail care este capabil să primească e-mailuri, să efectueze o analiză de sentiment și să determine dacă un e-mail necesită atenție imediată. Acum, trebuie doar să trimitem o alertă text atunci când un e-mail este deosebit de negativ.

Vom folosi Twilio pentru a trimite o alertă text. API-ul lor Python, care este documentat aici, este destul de simplu. Să modificăm ruta de analiză pentru a trimite o solicitare atunci când primește o solicitare urgentă.

 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"

Va trebui să setați variabilele de mediu la acreditările contului Twilio și să setați numărul de apel la un telefon pe care îl puteți verifica. Odată ce ați făcut asta, trimiteți un e-mail la punctul final de analiză și ar trebui să vedeți un text trimis la numărul de telefon în cauză.

Și am terminat!

Procesarea limbajului natural este ușoară cu Stanford NLP

În acest articol, ați învățat cum să creați un bot de analiză a sentimentelor de e-mail folosind biblioteca Stanford NLP. Biblioteca ajută la abstractizarea tuturor detaliilor esențiale ale procesării limbajului natural și vă permite să o utilizați ca element de bază pentru aplicațiile dvs. NLP.

Sper că această postare a demonstrat una dintre numeroasele aplicații potențiale uimitoare ale analizei sentimentelor și că aceasta vă inspiră să vă construiți propria aplicație NLP.

Puteți găsi codul pentru botul de analiză a sentimentelor de e-mail din acest tutorial NLP pe GitHub.

Înrudit: Patru capcane ale acurateței analizei sentimentelor