Jak zbudować bota do analizy nastrojów e-mail: samouczek NLP
Opublikowany: 2022-03-11W ciągu ostatnich kilku lat technologie przetwarzania języka naturalnego stały się dość wyrafinowane. Wielu, od gigantów technologicznych po hobbystów, spieszy się, aby zbudować bogate interfejsy, które mogą analizować, rozumieć i reagować na język naturalny. Alexa firmy Amazon, Cortana firmy Microsoft, Google Home firmy Google i Siri firmy Apple mają na celu zmianę sposobu interakcji z komputerami.
Analiza sentymentu, poddziedzina przetwarzania języka naturalnego, składa się z technik określających ton tekstu lub mowy. Dzisiaj, dzięki uczeniu maszynowemu i dużej ilości danych zebranych z mediów społecznościowych i witryn z recenzjami, możemy trenować modele, aby identyfikować sentyment do fragmentu języka naturalnego z wystarczającą dokładnością.
W tym samouczku dowiesz się, jak zbudować bota, który potrafi analizować nastroje otrzymywanych wiadomości e-mail i powiadamiać Cię o wiadomościach, które mogą od razu wymagać Twojej uwagi.
Analiza nastrojów w wiadomościach e-mail
Bot zostanie zbudowany przy użyciu połączenia programowania w Javie i Pythonie. Oba procesy będą komunikować się ze sobą za pomocą Thrift. Jeśli nie znasz jednego lub obu tych języków, nadal możesz czytać dalej, ponieważ podstawowe pojęcia tego artykułu będą dotyczyć również innych języków.
Aby określić, czy wiadomość e-mail wymaga Twojej uwagi, bot przeanalizuje ją i określi, czy istnieje silny negatywny ton. W razie potrzeby wyśle alert tekstowy.
Użyjemy Sendgrid, aby połączyć się z naszą skrzynką pocztową, a Twilio, aby wysłać alerty tekstowe.
Analiza nastrojów: zwodniczo prosty problem
Są słowa, które kojarzą nam się z pozytywnymi emocjami, jak miłość, radość, przyjemność. Są też słowa, które kojarzą nam się z negatywnymi emocjami, takimi jak nienawiść, smutek i ból. Dlaczego nie nauczyć modelu rozpoznawania tych słów i obliczania względnej częstotliwości i siły każdego pozytywnego i negatywnego słowa?
Cóż, jest z tym kilka problemów.
Po pierwsze, pojawia się problem negacji. Na przykład zdanie takie jak „Brzoskwinia nie jest zła” sugeruje pozytywną emocję, używając słowa, które najczęściej kojarzymy z negatywnym. Prosty model worka słów nie będzie w stanie rozpoznać negacji w tym zdaniu.
Co więcej, mieszane nastroje okazują się kolejnym problemem z naiwną analizą nastrojów. Na przykład zdanie takie jak „Brzoskwinia nie jest zła, ale jabłko jest naprawdę okropne” zawiera mieszane uczucia o mieszanej intensywności, które wchodzą ze sobą w interakcje. Proste podejście nie będzie w stanie rozwiązać połączonych sentymentów, różnej intensywności lub interakcji między sentymentami.
Analiza nastrojów za pomocą rekurencyjnej sieci tensorów neuronowych
Biblioteka Stanford Natural Language Processing do analizy sentymentu rozwiązuje te problemy przy użyciu Recursive Neural Tensor Network (RNTN).
Algorytm RNTN najpierw dzieli zdanie na pojedyncze słowa. Następnie buduje sieć neuronową, w której węzły są pojedynczymi słowami. Na koniec dodawana jest warstwa tensorowa, aby model mógł odpowiednio dostosować się do interakcji między słowami i frazami.
Wizualną demonstrację algorytmu można znaleźć na ich oficjalnej stronie internetowej.
Grupa Stanford NLP przeszkoliła sieć Recursive Neural Tensor Network przy użyciu ręcznie znakowanych recenzji filmów IMDB i stwierdziła, że ich model jest w stanie przewidzieć sentyment z bardzo dobrą dokładnością.
Bot odbierający e-maile
Pierwszą rzeczą, którą chcesz zrobić, to skonfigurować integrację poczty e-mail, aby dane mogły być przesyłane do bota.
Istnieje wiele sposobów na osiągnięcie tego, ale dla uproszczenia skonfigurujmy prosty serwer sieciowy i użyjmy przychodzącego zaczepu parsowania Sendgrid do przesyłania wiadomości e-mail do serwera. Możemy przekazywać wiadomości e-mail na adres analizy przychodzącej Sendgrid. Sendgrid wyśle następnie żądanie POST do naszego serwera internetowego, a my będziemy mogli przetwarzać dane za pośrednictwem naszego serwera.
Aby zbudować serwer, użyjemy Flask, prostego frameworka internetowego dla Pythona.
Oprócz budowy serwera WWW będziemy chcieli podłączyć usługę WWW do domeny. Dla zwięzłości pominiemy pisanie o tym w artykule. Więcej na ten temat możesz jednak przeczytać tutaj.
Budowanie serwera WWW w Flask jest niezwykle proste.
Po prostu utwórz plik app.py
i dodaj to do pliku:
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')
Jeśli wdrożymy tę aplikację za nazwą domeny i trafimy na punkt końcowy „/analyze”, powinieneś zobaczyć coś takiego:
> >> requests.post('http://sentiments.shanglunwang.com:5000/analyze').text 'Got it'
Następnie chcemy wysyłać e-maile do tego punktu końcowego.
Możesz znaleźć więcej dokumentacji tutaj, ale zasadniczo chcesz skonfigurować Sendgrid, aby był Twoim procesorem poczty e-mail i aby Sendgrid przekazywał wiadomości e-mail na nasz serwer WWW.
Oto moja konfiguracja na Sendgrid. Spowoduje to przekazywanie wiadomości e-mail na @sentibot.shanglunwang.com
jako żądania POST na adres „http://sentiments.shanglunwang.com/analyze”:
Możesz użyć dowolnej innej usługi, która obsługuje wysyłanie przychodzących wiadomości e-mail przez webhooki.
Po skonfigurowaniu wszystkiego spróbuj wysłać e-mail na swój adres Sendgrid. W dziennikach powinieneś zobaczyć coś takiego:
endpoint hit 2017-05-25 14:35:46
To wspaniale! Masz teraz bota, który może odbierać e-maile. To połowa tego, co staramy się zrobić.
Teraz chcesz dać temu botowi możliwość analizowania nastrojów w e-mailach.
Analiza nastrojów e-mailowych za pomocą Stanford NLP
Ponieważ biblioteka Stanford NLP jest napisana w Javie, będziemy chcieli zbudować silnik analizy w Javie.
Zacznijmy od pobrania biblioteki i modeli Stanford NLP w Maven. Utwórz nowy projekt Java, dodaj następujące elementy do swoich zależności Maven i zaimportuj:
<dependency> <groupId>edu.stanford.nlp</groupId> <artifactId>stanford-corenlp</artifactId> <version>3.6.0</version> </dependency>
Dostęp do aparatu analizy tonacji Stanford NLP można uzyskać, określając adnotator tonacji w kodzie inicjowania potoku. Adnotację można następnie pobrać jako strukturę drzewa.
Na potrzeby tego samouczka chcemy tylko poznać ogólny sentyment zdania, więc nie będziemy musieli analizować drzewa. Wystarczy spojrzeć na węzeł podstawowy.
To sprawia, że główny kod jest stosunkowo prosty:
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); } } }
Wypróbuj kilka zdań, a zobaczysz odpowiednie adnotacje. Uruchamianie przykładowych wyjść kodu:
Very Positive Negative
Integracja bota i silnika analizy
Mamy więc program analizujący sentyment napisany w Javie i bota pocztowego napisany w Pythonie. Jak sprawić, by ze sobą porozmawiali?
Istnieje wiele możliwych rozwiązań tego problemu, ale tutaj użyjemy Thrift. Uruchomimy Analizator Nastrojów jako serwer Thrift, a bota pocztowego jako klienta Thrift.
Thrift to generator kodu i protokół umożliwiający dwóm aplikacjom, często napisanym w różnych językach, komunikowanie się ze sobą za pomocą zdefiniowanego protokołu. Zespoły Polyglot używają Thrift do tworzenia sieci mikrousług, aby wykorzystać to, co najlepsze w każdym używanym języku.
Aby korzystać z Thrift, będziemy potrzebować dwóch rzeczy: pliku .thrift
do zdefiniowania punktów końcowych usługi oraz wygenerowanego kodu, aby skorzystać z protokołu zdefiniowanego w pliku .proto
. Dla usługi analizatora sentiment.thrift
wygląda tak:
namespace java sentiment namespace py sentiment service SentimentAnalysisService { string sentimentAnalyze(1:string sentence), }
Możemy wygenerować kod klienta i serwera za pomocą tego pliku .thrift. Biegać:

thrift-0.10.0.exe --gen py sentiment.thrift thrift-0.10.0.exe --gen java sentiment.thrift
Uwaga: wygenerowałem kod na komputerze z systemem Windows. Będziesz chciał użyć odpowiedniej ścieżki do pliku wykonywalnego Thrift w swoim środowisku.
Teraz dokonajmy odpowiednich zmian w silniku analizy, aby utworzyć serwer. Twój program Java powinien wyglądać tak:
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); } }
Ten program obsługi jest miejscem, w którym otrzymujemy żądanie analizy przez protokół 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; } }
Analizator używa biblioteki Stanford NLP do określenia tonacji tekstu i generuje ciąg zawierający adnotacje tonacji dla każdego zdania w tekście.
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(); } } }
Zauważ, że nie umieściłem tutaj pliku SentimentAnalysisService.java
, ponieważ jest to plik wygenerowany. Wygenerowany kod będziesz chciał umieścić w miejscu, w którym reszta kodu będzie miała do niego dostęp.
Teraz, gdy mamy już serwer, napiszmy klienta Pythona, który będzie korzystał z serwera.
klient.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'))
Uruchom to i powinieneś zobaczyć:
Very Positive
Świetnie! Teraz, gdy mamy uruchomiony serwer i rozmawiamy z klientem, zintegrujmy go z botem pocztowym, tworząc instancję klienta i przesyłając do niego wiadomość 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"
Teraz wdróż usługę Java na tym samym komputerze, na którym działa serwer sieci Web, uruchom usługę i uruchom ponownie aplikację. Wyślij e-maila do bota z testowym zdaniem, a w pliku dziennika powinieneś zobaczyć coś takiego:
Amazingly wonderfully positive and beautiful sentence. Very Positive
Analiza wiadomości e-mail
W porządku! Teraz mamy bota e-mailowego, który jest w stanie przeprowadzić analizę sentymentu! Możemy wysłać e-mail i otrzymać tag sentymentu za każde wysłane przez nas zdanie. Teraz przyjrzyjmy się, jak możemy sprawić, by inteligencja była aktywna.
Aby uprościć sprawę, skupmy się na e-mailach, w których występuje duża koncentracja negatywnych i bardzo negatywnych zdań. Użyjmy prostego systemu punktacji i powiedzmy, że jeśli wiadomość e-mail zawiera ponad 75% negatywnych zdań sentymentalnych, oznaczymy to jako potencjalny e-mail alarmowy, który może wymagać natychmiastowej odpowiedzi. Zaimplementujmy logikę scoringu w trasie analizy:
@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"
Powyższy kod zawiera kilka założeń, ale będzie działał w celach demonstracyjnych. Wyślij kilka e-maili do swojego bota, a w dziennikach powinieneś zobaczyć analizę wiadomości e-mail:
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
Wysyłanie alertu
Prawie skończyliśmy!
Zbudowaliśmy bota pocztowego, który jest w stanie odbierać wiadomości e-mail, przeprowadzać analizę nastrojów i określać, czy wiadomość e-mail wymaga natychmiastowej uwagi. Teraz wystarczy wysłać powiadomienie tekstowe, gdy wiadomość e-mail jest szczególnie negatywna.
Użyjemy Twilio do wysłania alertu tekstowego. Ich API Pythona, które jest tutaj udokumentowane, jest dość proste. Zmodyfikujmy trasę analizy, aby wysłać żądanie, gdy otrzyma pilne żądanie.
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"
Będziesz musiał ustawić zmienne środowiskowe na poświadczenia konta Twilio i ustawić numer dyżurny na telefon, który możesz sprawdzić. Gdy to zrobisz, wyślij wiadomość e-mail do punktu końcowego analizy, a powinieneś zobaczyć wiadomość tekstową wysyłaną na dany numer telefonu.
I gotowe!
Łatwe przetwarzanie języka naturalnego dzięki Stanford NLP
W tym artykule dowiedziałeś się, jak zbudować bota do analizy sentymentu w wiadomościach e-mail przy użyciu biblioteki Stanford NLP. Biblioteka pomaga wyabstrahować wszystkie najdrobniejsze szczegóły przetwarzania języka naturalnego i pozwala na użycie jej jako bloku konstrukcyjnego aplikacji NLP.
Mam nadzieję, że ten post zademonstrował jedno z wielu niesamowitych potencjalnych zastosowań analizy sentymentu i że to zainspiruje Cię do zbudowania własnej aplikacji NLP.
Kod bota do analizy nastrojów w wiadomościach e-mail można znaleźć w tym samouczku NLP w serwisie GitHub.