Cómo construir un bot de análisis de sentimiento de correo electrónico: un tutorial de PNL

Publicado: 2022-03-11

Las tecnologías de procesamiento del lenguaje natural se han vuelto bastante sofisticadas en los últimos años. Desde gigantes tecnológicos hasta aficionados, muchos se apresuran a crear interfaces ricas que puedan analizar, comprender y responder al lenguaje natural. Alexa de Amazon, Cortana de Microsoft, Google Home de Google y Siri de Apple tienen como objetivo cambiar la forma en que interactuamos con las computadoras.

El análisis de sentimientos, un subcampo del procesamiento del lenguaje natural, consta de técnicas que determinan el tono de un texto o discurso. Hoy, con el aprendizaje automático y grandes cantidades de datos recopilados de las redes sociales y los sitios de revisión, podemos entrenar modelos para identificar el sentimiento de un pasaje de lenguaje natural con bastante precisión.

Tutorial de bot de análisis de sentimiento de correo electrónico

En este tutorial, aprenderá cómo puede crear un bot que pueda analizar el sentimiento de los correos electrónicos que recibe y notificarle sobre los correos electrónicos que pueden requerir su atención de inmediato.

Análisis de sentimiento en correos electrónicos

El bot se construirá utilizando una combinación de desarrollo de Java y Python. Los dos procesos se comunicarán entre sí mediante Thrift. Si no está familiarizado con uno o ambos de estos idiomas, aún puede seguir leyendo, ya que los conceptos fundamentales de este artículo también se aplicarán a otros idiomas.

Para determinar si un correo electrónico necesita su atención, el bot lo analizará y determinará si hay un tono negativo fuerte. Luego enviará una alerta de texto si es necesario.

Usaremos Sendgrid para conectarnos a nuestro buzón y Twilio para enviar alertas de texto.

Análisis de sentimiento: un problema engañosamente simple

Hay palabras que asociamos con emociones positivas, como el amor, la alegría y el placer. Y hay palabras que asociamos con emociones negativas, como el odio, la tristeza y el dolor. ¿Por qué no entrenar al modelo para que reconozca estas palabras y cuente la frecuencia relativa y la fuerza de cada palabra positiva y negativa?

Bueno, hay un par de problemas con eso.

Primero, hay un problema de negación. Por ejemplo, una oración como “El durazno no está mal” implica una emoción positiva usando una palabra que solemos asociar con ser negativa. Un modelo simple de bolsa de palabras no podrá reconocer la negación en esta oración.

Además, los sentimientos mixtos demuestran ser otro problema con el análisis de sentimiento ingenuo. Por ejemplo, una oración como “El melocotón no es malo, pero la manzana es verdaderamente terrible” contiene sentimientos encontrados de intensidades mezcladas que interactúan entre sí. Un enfoque simple no podrá resolver los sentimientos combinados, la diferente intensidad o las interacciones entre los sentimientos.

Análisis de sentimiento utilizando la red de tensores neuronales recursivos

La biblioteca de procesamiento de lenguaje natural de Stanford para el análisis de sentimientos resuelve estos problemas mediante una red de tensor neuronal recursivo (RNTN).

RNTN en una oración

El algoritmo RNTN primero divide una oración en palabras individuales. Luego construye una red neuronal donde los nodos son las palabras individuales. Finalmente, se agrega una capa de tensor para que el modelo pueda ajustarse adecuadamente a las interacciones entre las palabras y las frases.

Puede encontrar una demostración visual del algoritmo en su sitio web oficial.

El grupo de NLP de Stanford entrenó la red de tensores neuronales recursivos utilizando reseñas de películas de IMDB etiquetadas manualmente y descubrió que su modelo puede predecir el sentimiento con muy buena precisión.

Bot que recibe correos electrónicos

Lo primero que desea hacer es configurar la integración de correo electrónico para que los datos se puedan canalizar a su bot.

Hay muchas maneras de lograr esto, pero en aras de la simplicidad, configuremos un servidor web simple y usemos el gancho de análisis entrante de Sendgrid para canalizar los correos electrónicos al servidor. Podemos reenviar correos electrónicos a la dirección de análisis entrante de Sendgrid. Sendgrid luego enviará una solicitud POST a nuestro servidor web y luego podremos procesar los datos a través de nuestro servidor.

Para construir el servidor, usaremos Flask, un marco web simple para Python.

Además de construir el servidor web, querremos conectar el servicio web a un dominio. Por brevedad, omitiremos escribir sobre esto en el artículo. Sin embargo, puedes leer más al respecto aquí.

Construir un servidor web en Flask es increíblemente simple.

Simplemente cree un app.py y agréguelo al archivo:

 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 implementamos esta aplicación detrás de un nombre de dominio y llegamos al punto final "/ analizar", debería ver algo como esto:

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

A continuación, queremos enviar correos electrónicos a este punto final.

Puede encontrar más documentación aquí, pero esencialmente desea configurar Sendgrid para que sea su procesador de correo electrónico y hacer que Sendgrid reenvíe los correos electrónicos a nuestro servidor web.

Aquí está mi configuración en Sendgrid. Esto reenviará correos electrónicos a @sentibot.shanglunwang.com como solicitudes POST a "http://sentiments.shanglunwang.com/analyze":

Configuración de la red de envío

Puede usar cualquier otro servicio que admita el envío de correos electrónicos entrantes a través de webhooks.

Después de configurar todo, intente enviar un correo electrónico a su dirección de Sendgrid. Debería ver algo como esto en los registros:

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

¡Eso es genial! Ahora tiene un bot que puede recibir correos electrónicos. Eso es la mitad de lo que estamos tratando de hacer.

Ahora, desea darle a este bot la capacidad de analizar los sentimientos en los correos electrónicos.

Análisis de sentimiento de correo electrónico con Stanford NLP

Dado que la biblioteca Stanford NLP está escrita en Java, queremos construir el motor de análisis en Java.

Comencemos descargando la biblioteca y los modelos de NLP de Stanford en Maven. Cree un nuevo proyecto Java, agregue lo siguiente a sus dependencias de Maven e importe:

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

Se puede acceder al motor de análisis de opiniones de Stanford NLP especificando el anotador de opiniones en el código de inicialización de canalización. A continuación, la anotación se puede recuperar como una estructura de árbol.

Para los propósitos de este tutorial, solo queremos conocer el sentimiento general de una oración, por lo que no necesitaremos analizar el árbol. Solo tenemos que mirar el nodo base.

Esto hace que el código principal sea relativamente 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); } } }

Pruebe algunas oraciones y debería ver las anotaciones apropiadas. Ejecutando los resultados del código de ejemplo:

 Very Positive Negative

Integrando el Bot y el Motor de Análisis

Así que tenemos un programa analizador de sentimientos escrito en Java y un bot de correo electrónico escrito en Python. ¿Cómo hacemos para que hablen entre ellos?

Hay muchas soluciones posibles a este problema, pero aquí usaremos Thrift. Activaremos el Analizador de sentimientos como un servidor Thrift y el bot de correo electrónico como un cliente Thrift.

Thrift es un generador de código y un protocolo que se utiliza para permitir que dos aplicaciones, a menudo escritas en diferentes idiomas, puedan comunicarse entre sí mediante un protocolo definido. Los equipos de Polyglot usan Thrift para construir redes de microservicios para aprovechar lo mejor de cada idioma que usan.

Para usar Thrift, necesitaremos dos cosas: un archivo .thrift para definir los puntos finales del servicio y un código generado para usar el protocolo definido en el archivo .proto . Para el servicio del analizador, sentiment.thrift tiene este aspecto:

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

Podemos generar código de cliente y servidor utilizando este archivo .thrift. Correr:

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

Nota: generé el código en una máquina con Windows. Querrá utilizar la ruta adecuada al ejecutable de Thrift en su entorno.

Ahora, hagamos los cambios apropiados en el motor de análisis para crear un servidor. Su programa Java debería verse así:

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

Este controlador es donde recibimos la solicitud de análisis a través del protocolo 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; } }

El Analizador utiliza la biblioteca NLP de Stanford para determinar la opinión del texto y produce una cadena que contiene las anotaciones de opinión para cada oración del texto.

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

Tenga en cuenta que no incluí el archivo SentimentAnalysisService.java aquí ya que es un archivo generado. Deberá colocar el código generado en un lugar donde el resto de su código pueda acceder a él.

Ahora que tenemos el servidor activo, escribamos un cliente de Python para usar el servidor.

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

Ejecuta esto y deberías ver:

 Very Positive

¡Genial! Ahora que tenemos el servidor ejecutándose y comunicándose con el cliente, integrémoslo con el bot de correo electrónico instanciando un cliente y canalizando el correo electrónico hacia él.

 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"

Ahora implemente su servicio Java en la misma máquina donde está ejecutando el servidor web, inicie el servicio y reinicie la aplicación. Envíe un correo electrónico al bot con una oración de prueba y debería ver algo como esto en el archivo de registro:

 Amazingly wonderfully positive and beautiful sentence. Very Positive

Analizando el correo electrónico

¡Todo bien! ¡Ahora tenemos un bot de correo electrónico que puede realizar análisis de sentimientos! Podemos enviar un correo electrónico y recibir una etiqueta de sentimiento por cada oración que enviamos. Ahora, exploremos cómo podemos hacer que la inteligencia sea accionable.

Para simplificar las cosas, concentrémonos en los correos electrónicos donde hay una alta concentración de oraciones negativas y muy negativas. Usemos un sistema de puntuación simple y digamos que si un correo electrónico contiene más del 75 % de oraciones con opiniones negativas, lo marcaremos como un correo electrónico de alarma potencial que puede requerir una respuesta inmediata. Implementemos la lógica de puntuación en la ruta de análisis:

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

El código anterior hace algunas suposiciones, pero funcionará con fines de demostración. Envíe un par de correos electrónicos a su bot y debería ver el análisis de correo electrónico en los registros:

 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

Envío de una alerta

¡Ya casi hemos terminado!

Hemos creado un bot de correo electrónico que puede recibir correos electrónicos, realizar análisis de opiniones y determinar si un correo electrónico requiere atención inmediata. Ahora, solo tenemos que enviar una alerta de texto cuando un correo electrónico es particularmente negativo.

Usaremos Twilio para enviar una alerta de texto. Su API de Python, que se documenta aquí, es bastante sencilla. Modifiquemos la ruta de análisis para enviar una solicitud cuando reciba una solicitud 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"

Deberá configurar sus variables de entorno para las credenciales de su cuenta de Twilio y configurar el número de guardia en un teléfono que pueda verificar. Una vez que haya hecho eso, envíe un correo electrónico al extremo del análisis y debería ver que se envía un mensaje de texto al número de teléfono en cuestión.

¡Y hemos terminado!

Procesamiento del lenguaje natural simplificado con Stanford NLP

En este artículo, aprendió a crear un bot de análisis de opiniones de correo electrónico utilizando la biblioteca NLP de Stanford. La biblioteca ayuda a abstraer todos los detalles esenciales del procesamiento del lenguaje natural y le permite usarla como un bloque de construcción para sus aplicaciones NLP.

Espero que esta publicación haya demostrado una de las muchas aplicaciones potenciales asombrosas del análisis de sentimientos, y que esto lo inspire a crear su propia aplicación de PNL.

Puede encontrar el código para el bot de análisis de opiniones de correo electrónico en este tutorial de NLP en GitHub.

Relacionado: Cuatro trampas de la precisión del análisis de sentimiento