Capítulo 5: Proyectos de Integración de Imagen y Audio
5.4 Análisis de Sentimiento de Audio con OpenAI
En esta sección, exploraremos cómo construir una aplicación web sofisticada en Flask que realiza análisis de sentimiento en contenido de audio utilizando las potentes APIs de OpenAI. Esta integración combina dos tecnologías clave: primero, la aplicación utiliza la API Whisper de OpenAI para convertir palabras habladas en texto escrito mediante una transcripción precisa. Luego, aprovecha los modelos de lenguaje de OpenAI para analizar el tono emocional y el sentimiento del contenido transcrito.
El flujo del proceso es sencillo pero potente: los usuarios suben un archivo de audio, que se transcribe a texto, y luego la aplicación aplica procesamiento de lenguaje natural para determinar si el mensaje del hablante transmite un sentimiento positivo, negativo o neutral. Este análisis de dos pasos proporciona información valiosa sobre el contenido emocional de las comunicaciones habladas, haciéndolo útil para varias aplicaciones como análisis de retroalimentación de clientes, investigación de mercado y moderación de contenido.
5.4.1 Lo que Construirás
La aplicación web proporciona una solución integral de análisis de audio con varias funcionalidades clave. Cuando los usuarios interactúan con la plataforma, realiza la siguiente secuencia de operaciones:
- Recepción y Procesamiento de Cargas de Audio: La aplicación cuenta con una interfaz web sofisticada que maneja cargas de archivos de audio con amplio soporte de formatos. Los usuarios pueden enviar archivos en formatos populares como MP3 (ideal para audio comprimido), WAV (perfecto para audio sin comprimir de alta calidad) y M4A (optimizado para grabaciones de voz). La interfaz incluye validación de archivos, verificación de tamaño y formato para asegurar un procesamiento fluido.
- Sistema Seguro de Gestión de Archivos: Al recibir una carga, la aplicación implementa un sistema robusto de almacenamiento temporal. Los archivos se almacenan en un directorio seguro con controles de acceso apropiados, utilizando protocolos automáticos de limpieza para prevenir el desbordamiento de almacenamiento. El sistema incluye mecanismos de manejo de errores para cargas fallidas, archivos corruptos y escenarios de tiempo de espera, asegurando una operación confiable incluso bajo carga pesada.
- Transcripción Avanzada de Audio: La integración con la API Whisper de OpenAI proporciona capacidades de reconocimiento de voz de última generación. Este modelo sofisticado sobresale en el manejo de varios acentos, dialectos y condiciones de ruido de fondo, entregando transcripciones precisas en múltiples idiomas. El sistema procesa el audio en fragmentos para un rendimiento óptimo e incluye seguimiento de progreso para archivos más largos.
- Análisis Integral de Sentimiento: La aplicación aprovecha el procesamiento avanzado de lenguaje natural de GPT-4 a través de la API de Chat Completion. Este análisis va más allá de la clasificación básica positivo/negativo, examinando pistas contextuales, matices emocionales y sutilezas lingüísticas. El sistema considera factores como el tono, la intensidad y el contexto semántico para proporcionar una comprensión matizada del sentimiento.
- Interfaz de Resultados Amigable: La aplicación presenta los resultados del análisis a través de una interfaz intuitiva y bien diseñada. Los usuarios reciben tanto la transcripción completa como un desglose detallado del sentimiento, con indicadores visuales claros para diferentes categorías emocionales. La interfaz incluye opciones para descargar resultados, compartir informes de análisis y ver análisis históricos cuando corresponda.
Esta revolucionaria combinación de tecnologías de transcripción de audio y análisis de lenguaje revoluciona cómo procesamos y entendemos el contenido hablado. Las aplicaciones abarcan múltiples industrias, ofreciendo perspectivas y mejoras de eficiencia sin precedentes:
- Análisis de retroalimentación de clientes desde grabaciones de voz - Esta aplicación transforma cómo las empresas manejan las interacciones con clientes. Los centros de llamadas y departamentos de servicio al cliente ahora pueden procesar automáticamente miles de llamadas para:
- Rastrear tendencias de satisfacción del cliente a lo largo del tiempo
- Identificar puntos específicos de dolor en las experiencias del cliente
- Generar perspectivas accionables para mejorar el servicio
- Entrenar representantes de servicio al cliente más efectivamente
- Detección de tonos emocionales en contenido hablado para análisis de medios - Esta capacidad proporciona a las empresas de medios herramientas sofisticadas para evaluación de contenido:
- Medir el compromiso emocional de la audiencia a lo largo del contenido
- Analizar la autenticidad y credibilidad del hablante
- Asegurar la consistencia del mensaje de marca a través de diferentes medios
- Optimizar el contenido para máximo impacto emocional
- Evaluación del sentimiento de contenido de audio en podcasts o entrevistas - Esta característica revoluciona el análisis de contenido al:
- Procesar horas de contenido en minutos
- Identificar momentos clave de significancia emocional
- Rastrear cambios de sentimiento a lo largo de las discusiones
- Permitir decisiones de estrategia de contenido basadas en datos
Tecnologías Utilizadas:
- Flask: Un marco de trabajo web de Python.
- API de OpenAI:
- Whisper para transcripción de audio.
- GPT-4 (o similar) para análisis de sentimiento.
- HTML: Para estructurar la página web.
- CSS: Para estilizar la página web.
Estructura del Proyecto:
El proyecto tendrá la siguiente estructura de archivos:
/audio_sentiment_analyzer
│
├── app.py
├── .env
└── templates/
└── index.html
app.py
: El archivo Python que contiene el código de la aplicación Flask..env
: Un archivo para almacenar la clave API de OpenAI.templates/
: Un directorio para almacenar las plantillas HTML.templates/index.html
: La plantilla HTML para la página principal.
5.4.2 Implementación Paso a Paso
Paso 1: Instalar Paquetes Requeridos
Descarga el archivo de audio de muestra: https://files.cuantum.tech/audio/someone-speaking.mp3
Instala las bibliotecas Python necesarias:
pip install flask openai python-dotenv
Paso 2: Configurar Variables de Entorno
Crea un archivo .env
en tu directorio del proyecto y añade tu clave API de OpenAI:
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
Paso 3: Crear la Aplicación Flask (app.py)
Crea un archivo Python llamado app.py
y añade el siguiente código:
from flask import Flask, request, render_template, jsonify
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional, Dict
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
app = Flask(__name__)
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ALLOWED_EXTENSIONS = {'mp3', 'mp4', 'wav', 'm4a'} # Allowed audio file extensions
def allowed_file(filename: str) -> bool:
"""
Checks if the uploaded file has an allowed extension.
Args:
filename (str): The name of the file.
Returns:
bool: True if the file has an allowed extension, False otherwise.
"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def transcribe_audio(file_path: str) -> Optional[str]:
"""
Transcribes an audio file using OpenAI's Whisper API.
Args:
file_path (str): The path to the audio file.
Returns:
Optional[str]: The transcribed text, or None on error.
"""
try:
logger.info(f"Transcribing audio file: {file_path}")
audio_file = open(file_path, "rb")
response = openai.Audio.transcriptions.create(
model="whisper-1",
file=audio_file,
)
transcript = response.text
logger.info(f"Transcription successful. Length: {len(transcript)} characters.")
return transcript
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during transcription: {e}")
return None
def analyze_sentiment(text: str) -> Optional[str]:
"""
Analyzes the sentiment of a given text using OpenAI's Chat Completion API.
Args:
text (str): The text to analyze.
Returns:
Optional[str]: The sentiment analysis result, or None on error.
"""
try:
logger.info("Analyzing sentiment of transcribed text.")
response = openai.chat.completions.create(
model="gpt-4", # Or another suitable chat model
messages=[
{
"role": "system",
"content": "You are a sentiment analysis expert. Provide a concise sentiment analysis of the text. Your response should be one of the following: 'Positive', 'Negative', or 'Neutral'.",
},
{"role": "user", "content": text},
],
temperature=0.2, # Keep the output focused
max_tokens=20
)
sentiment = response.choices[0].message.content
logger.info(f"Sentiment analysis result: {sentiment}")
return sentiment
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during sentiment analysis: {e}")
return None
@app.route("/", methods=["GET", "POST"])
def index():
"""
Handles the main route for the web application.
Allows users to upload an audio file, transcribes it, and analyzes the sentiment.
"""
sentiment = None
error_message = None
if request.method == "POST":
if 'audio_file' not in request.files:
error_message = "No file part"
logger.warning(error_message)
return render_template("index.html", error=error_message)
file = request.files['audio_file']
if file.filename == '':
error_message = "No file selected"
logger.warning(error_message)
return render_template("index.html", error=error_message)
if file and allowed_file(file.filename):
try:
# Securely save the uploaded file to a temporary location
temp_file_path = os.path.join(app.root_path, "temp_audio." + file.filename.rsplit('.', 1)[1].lower())
file.save(temp_file_path)
transcript = transcribe_audio(temp_file_path) # Transcribe the audio
if not transcript:
error_message = "Transcription failed. Please try again."
return render_template("index.html", error=error_message)
sentiment = analyze_sentiment(transcript)
if not sentiment:
error_message = "Sentiment analysis failed. Please try again."
return render_template("index.html", error=error_message)
# Optionally, delete the temporary file after processing
os.remove(temp_file_path)
except Exception as e:
error_message = f"An error occurred: {e}"
logger.error(error_message)
return render_template("index.html", error=error_message)
else:
error_message = "Invalid file type. Please upload a valid audio file (MP3, MP4, WAV, M4A)."
logger.warning(error_message)
return render_template("index.html", error=error_message)
return render_template("index.html", sentiment=sentiment, error=error_message)
@app.errorhandler(500)
def internal_server_error(e):
"""Handles internal server errors."""
logger.error(f"Internal Server Error: {e}")
return render_template("error.html", error="Internal Server Error"), 500
if __name__ == "__main__":
app.run(debug=True)
Desglose del Código:
- Declaraciones de Importación: Importa los módulos necesarios de Flask, la biblioteca OpenAI,
os
,dotenv
,logging
, yOptional
yDict
para sugerencia de tipos. - Variables de Entorno: Carga la clave API de OpenAI desde el archivo
.env
. - Aplicación Flask: Crea una instancia de la aplicación Flask.
- Configuración de Registro: Configura el registro para la aplicación.
allowed_file
Función: Verifica si el archivo subido tiene una extensión de audio permitida (MP3, MP4, WAV, M4A).transcribe_audio
Función: Transcribe un archivo de audio usando la API Whisper de OpenAI. Registra la ruta del archivo y cualquier error durante la transcripción.analyze_sentiment
Función:def analyze_sentiment(text: str) -> Optional[str]:
: Define una función para analizar el sentimiento de un texto usando la API de Chat Completion de OpenAI.- Toma el texto transcrito como entrada.
- Envía una solicitud a la API de Chat Completion con un mensaje del sistema que instruye al modelo para realizar análisis de sentimiento. La temperatura se establece en 0.2 para hacer la salida más precisa, y
max_tokens
está limitado a 20 para mantener la respuesta concisa. - Extrae el sentimiento de la respuesta de la API.
- Registra el resultado del análisis de sentimiento.
- Incluye manejo de errores para errores de la API de OpenAI y otras excepciones.
index
Ruta:- Maneja solicitudes GET y POST.
- Para solicitudes GET, renderiza la página HTML inicial.
- Para solicitudes POST (cuando el usuario sube un archivo de audio):
- Valida el archivo subido.
- Guarda el archivo temporalmente.
- Llama a
transcribe_audio()
para transcribir el audio. - Llama a
analyze_sentiment()
para analizar el texto transcrito. - Renderiza la plantilla HTML, pasando el resultado del análisis de sentimiento o cualquier mensaje de error.
@app.errorhandler(500)
: Maneja errores internos del servidor registrando el error y renderizando una página de error amigable para el usuario.if __name__ == "__main__":
: Inicia el servidor de desarrollo Flask si el script se ejecuta directamente.
Paso 4: Crear la Plantilla HTML (templates/index.html)
Crea una carpeta llamada templates
en el mismo directorio que app.py
. Dentro de la carpeta templates
, crea un archivo llamado index.html
con el siguiente código HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audio Sentiment Analyzer</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
/* --- General Styles --- */
body {
font-family: 'Inter', sans-serif;
padding: 40px;
background-color: #f9fafb;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
color: #374151;
}
.container {
max-width: 800px;
width: 95%;
background-color: #fff;
padding: 2rem;
border-radius: 0.75rem;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05);
text-align: center;
}
h2 {
font-size: 2.25rem;
font-weight: 600;
margin-bottom: 1.5rem;
color: #1e293b;
}
p {
color: #6b7280;
margin-bottom: 1rem;
}
/* --- Form Styles --- */
form {
margin-top: 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
label {
font-size: 1rem;
font-weight: 600;
color: #4b5563;
margin-bottom: 0.25rem;
display: block;
text-align: left;
width: 100%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
input[type="file"] {
width: 100%;
max-width: 400px;
padding: 0.75rem;
border-radius: 0.5rem;
border: 1px solid #d1d5db;
font-size: 1rem;
margin-bottom: 0.25rem;
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
background-color: #4f46e5;
color: #fff;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s ease;
border: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
margin-top: 1rem;
}
input[type="submit"]:hover {
background-color: #4338ca;
}
input[type="submit"]:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3);
}
/* --- Result Styles --- */
.result-container {
margin-top: 2rem;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
background-color: #f8fafc;
}
.result-title{
font-size: 1.25rem;
font-weight: 600;
color: #1e293b;
margin-bottom: 0.75rem;
}
.sentiment-positive {
color: #16a34a;
font-weight: 600;
}
.sentiment-negative {
color: #dc2626;
font-weight: 600;
}
.sentiment-neutral {
color: #71717a;
font-weight: 600;
}
/* --- Error Styles --- */
.error-message {
color: #dc2626;
margin-top: 1rem;
padding: 0.75rem;
background-color: #fee2e2;
border-radius: 0.375rem;
border: 1px solid #fecaca;
text-align: center;
}
/* --- Responsive Adjustments --- */
@media (max-width: 768px) {
.container {
padding: 20px;
}
form {
gap: 1rem;
}
input[type="file"] {
max-width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h2>🎙️ Audio Sentiment Analyzer</h2>
<p> Upload an audio file to analyze the sentiment of the spoken content. Supported formats: MP3, MP4, WAV, M4A </p>
<form method="POST" enctype="multipart/form-data">
<label for="audio_file">Upload an audio file:</label><br>
<input type="file" name="audio_file" accept="audio/*" required><br><br>
<input type="submit" value="Analyze Sentiment">
</form>
{% if sentiment %}
<div class="result-container">
<h3 class = "result-title">Sentiment Analysis Result:</h3>
<p class="sentiment-{{ sentiment.lower() }}"> {{ sentiment }} </p>
</div>
{% endif %}
{% if error %}
<div class="error-message">{{ error }}</div>
{% endif %}
</div>
</body>
</html>
Elementos clave en la plantilla HTML:
- Estructura HTML:
- La sección
<head>
define el título, enlaza una hoja de estilos CSS y configura el viewport para que el diseño sea adaptable. - El
<body>
contiene el contenido visible, incluido un formulario para subir archivos de audio y una sección para mostrar el resultado del análisis de sentimiento.
- La sección
- Estilo CSS:
- Diseño moderno: El CSS ha sido actualizado con un diseño más actual.
- Diseño responsivo: El diseño se adapta mejor a pantallas pequeñas.
- Experiencia de usuario: Se ha mejorado el estilo de los formularios y los campos de entrada para facilitar su uso.
- Visualización clara de errores: Los mensajes de error están estilizados para que sean fácilmente visibles.ndicador de sentimiento: Los colores de los resultados cambian según el sentimiento detectado.
- Formulario:
- Se utiliza un
<form>
conenctype="multipart/form-data"
para gestionar la carga de archivos. - Un
<label>
y un<input type="file">
permiten al usuario seleccionar un archivo de audio. El atributoaccept="audio/*"
restringe la carga a archivos de audio. - Un botón
<input type="submit">
permite al usuario enviar el formulario.
- Se utiliza un
- Visualización del sentimiento:
- Se utiliza un
<div class="result-container">
para mostrar el resultado del análisis de sentimiento. El color del resultado cambia según el sentimiento detectado.
- Se utiliza un
- Manejo de errores:
- Se utiliza un
<div class="error-message">
para mostrar los mensajes de error al usuario.
- Se utiliza un
Pruébalo
- Guarda los archivos como
app.py
ytemplates/index.html
. - Asegúrate de tener tu clave de API de OpenAI en el archivo
.env
. - Ejecuta la aplicación:
python app.py
- Abre
http://localhost:5000
en tu navegador. - Sube un archivo de audio (por ejemplo, una grabación de voz o el archivo .mp3 de muestra).
- Visualiza el resultado del análisis de sentimiento mostrado en la página.
5.4 Análisis de Sentimiento de Audio con OpenAI
En esta sección, exploraremos cómo construir una aplicación web sofisticada en Flask que realiza análisis de sentimiento en contenido de audio utilizando las potentes APIs de OpenAI. Esta integración combina dos tecnologías clave: primero, la aplicación utiliza la API Whisper de OpenAI para convertir palabras habladas en texto escrito mediante una transcripción precisa. Luego, aprovecha los modelos de lenguaje de OpenAI para analizar el tono emocional y el sentimiento del contenido transcrito.
El flujo del proceso es sencillo pero potente: los usuarios suben un archivo de audio, que se transcribe a texto, y luego la aplicación aplica procesamiento de lenguaje natural para determinar si el mensaje del hablante transmite un sentimiento positivo, negativo o neutral. Este análisis de dos pasos proporciona información valiosa sobre el contenido emocional de las comunicaciones habladas, haciéndolo útil para varias aplicaciones como análisis de retroalimentación de clientes, investigación de mercado y moderación de contenido.
5.4.1 Lo que Construirás
La aplicación web proporciona una solución integral de análisis de audio con varias funcionalidades clave. Cuando los usuarios interactúan con la plataforma, realiza la siguiente secuencia de operaciones:
- Recepción y Procesamiento de Cargas de Audio: La aplicación cuenta con una interfaz web sofisticada que maneja cargas de archivos de audio con amplio soporte de formatos. Los usuarios pueden enviar archivos en formatos populares como MP3 (ideal para audio comprimido), WAV (perfecto para audio sin comprimir de alta calidad) y M4A (optimizado para grabaciones de voz). La interfaz incluye validación de archivos, verificación de tamaño y formato para asegurar un procesamiento fluido.
- Sistema Seguro de Gestión de Archivos: Al recibir una carga, la aplicación implementa un sistema robusto de almacenamiento temporal. Los archivos se almacenan en un directorio seguro con controles de acceso apropiados, utilizando protocolos automáticos de limpieza para prevenir el desbordamiento de almacenamiento. El sistema incluye mecanismos de manejo de errores para cargas fallidas, archivos corruptos y escenarios de tiempo de espera, asegurando una operación confiable incluso bajo carga pesada.
- Transcripción Avanzada de Audio: La integración con la API Whisper de OpenAI proporciona capacidades de reconocimiento de voz de última generación. Este modelo sofisticado sobresale en el manejo de varios acentos, dialectos y condiciones de ruido de fondo, entregando transcripciones precisas en múltiples idiomas. El sistema procesa el audio en fragmentos para un rendimiento óptimo e incluye seguimiento de progreso para archivos más largos.
- Análisis Integral de Sentimiento: La aplicación aprovecha el procesamiento avanzado de lenguaje natural de GPT-4 a través de la API de Chat Completion. Este análisis va más allá de la clasificación básica positivo/negativo, examinando pistas contextuales, matices emocionales y sutilezas lingüísticas. El sistema considera factores como el tono, la intensidad y el contexto semántico para proporcionar una comprensión matizada del sentimiento.
- Interfaz de Resultados Amigable: La aplicación presenta los resultados del análisis a través de una interfaz intuitiva y bien diseñada. Los usuarios reciben tanto la transcripción completa como un desglose detallado del sentimiento, con indicadores visuales claros para diferentes categorías emocionales. La interfaz incluye opciones para descargar resultados, compartir informes de análisis y ver análisis históricos cuando corresponda.
Esta revolucionaria combinación de tecnologías de transcripción de audio y análisis de lenguaje revoluciona cómo procesamos y entendemos el contenido hablado. Las aplicaciones abarcan múltiples industrias, ofreciendo perspectivas y mejoras de eficiencia sin precedentes:
- Análisis de retroalimentación de clientes desde grabaciones de voz - Esta aplicación transforma cómo las empresas manejan las interacciones con clientes. Los centros de llamadas y departamentos de servicio al cliente ahora pueden procesar automáticamente miles de llamadas para:
- Rastrear tendencias de satisfacción del cliente a lo largo del tiempo
- Identificar puntos específicos de dolor en las experiencias del cliente
- Generar perspectivas accionables para mejorar el servicio
- Entrenar representantes de servicio al cliente más efectivamente
- Detección de tonos emocionales en contenido hablado para análisis de medios - Esta capacidad proporciona a las empresas de medios herramientas sofisticadas para evaluación de contenido:
- Medir el compromiso emocional de la audiencia a lo largo del contenido
- Analizar la autenticidad y credibilidad del hablante
- Asegurar la consistencia del mensaje de marca a través de diferentes medios
- Optimizar el contenido para máximo impacto emocional
- Evaluación del sentimiento de contenido de audio en podcasts o entrevistas - Esta característica revoluciona el análisis de contenido al:
- Procesar horas de contenido en minutos
- Identificar momentos clave de significancia emocional
- Rastrear cambios de sentimiento a lo largo de las discusiones
- Permitir decisiones de estrategia de contenido basadas en datos
Tecnologías Utilizadas:
- Flask: Un marco de trabajo web de Python.
- API de OpenAI:
- Whisper para transcripción de audio.
- GPT-4 (o similar) para análisis de sentimiento.
- HTML: Para estructurar la página web.
- CSS: Para estilizar la página web.
Estructura del Proyecto:
El proyecto tendrá la siguiente estructura de archivos:
/audio_sentiment_analyzer
│
├── app.py
├── .env
└── templates/
└── index.html
app.py
: El archivo Python que contiene el código de la aplicación Flask..env
: Un archivo para almacenar la clave API de OpenAI.templates/
: Un directorio para almacenar las plantillas HTML.templates/index.html
: La plantilla HTML para la página principal.
5.4.2 Implementación Paso a Paso
Paso 1: Instalar Paquetes Requeridos
Descarga el archivo de audio de muestra: https://files.cuantum.tech/audio/someone-speaking.mp3
Instala las bibliotecas Python necesarias:
pip install flask openai python-dotenv
Paso 2: Configurar Variables de Entorno
Crea un archivo .env
en tu directorio del proyecto y añade tu clave API de OpenAI:
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
Paso 3: Crear la Aplicación Flask (app.py)
Crea un archivo Python llamado app.py
y añade el siguiente código:
from flask import Flask, request, render_template, jsonify
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional, Dict
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
app = Flask(__name__)
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ALLOWED_EXTENSIONS = {'mp3', 'mp4', 'wav', 'm4a'} # Allowed audio file extensions
def allowed_file(filename: str) -> bool:
"""
Checks if the uploaded file has an allowed extension.
Args:
filename (str): The name of the file.
Returns:
bool: True if the file has an allowed extension, False otherwise.
"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def transcribe_audio(file_path: str) -> Optional[str]:
"""
Transcribes an audio file using OpenAI's Whisper API.
Args:
file_path (str): The path to the audio file.
Returns:
Optional[str]: The transcribed text, or None on error.
"""
try:
logger.info(f"Transcribing audio file: {file_path}")
audio_file = open(file_path, "rb")
response = openai.Audio.transcriptions.create(
model="whisper-1",
file=audio_file,
)
transcript = response.text
logger.info(f"Transcription successful. Length: {len(transcript)} characters.")
return transcript
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during transcription: {e}")
return None
def analyze_sentiment(text: str) -> Optional[str]:
"""
Analyzes the sentiment of a given text using OpenAI's Chat Completion API.
Args:
text (str): The text to analyze.
Returns:
Optional[str]: The sentiment analysis result, or None on error.
"""
try:
logger.info("Analyzing sentiment of transcribed text.")
response = openai.chat.completions.create(
model="gpt-4", # Or another suitable chat model
messages=[
{
"role": "system",
"content": "You are a sentiment analysis expert. Provide a concise sentiment analysis of the text. Your response should be one of the following: 'Positive', 'Negative', or 'Neutral'.",
},
{"role": "user", "content": text},
],
temperature=0.2, # Keep the output focused
max_tokens=20
)
sentiment = response.choices[0].message.content
logger.info(f"Sentiment analysis result: {sentiment}")
return sentiment
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during sentiment analysis: {e}")
return None
@app.route("/", methods=["GET", "POST"])
def index():
"""
Handles the main route for the web application.
Allows users to upload an audio file, transcribes it, and analyzes the sentiment.
"""
sentiment = None
error_message = None
if request.method == "POST":
if 'audio_file' not in request.files:
error_message = "No file part"
logger.warning(error_message)
return render_template("index.html", error=error_message)
file = request.files['audio_file']
if file.filename == '':
error_message = "No file selected"
logger.warning(error_message)
return render_template("index.html", error=error_message)
if file and allowed_file(file.filename):
try:
# Securely save the uploaded file to a temporary location
temp_file_path = os.path.join(app.root_path, "temp_audio." + file.filename.rsplit('.', 1)[1].lower())
file.save(temp_file_path)
transcript = transcribe_audio(temp_file_path) # Transcribe the audio
if not transcript:
error_message = "Transcription failed. Please try again."
return render_template("index.html", error=error_message)
sentiment = analyze_sentiment(transcript)
if not sentiment:
error_message = "Sentiment analysis failed. Please try again."
return render_template("index.html", error=error_message)
# Optionally, delete the temporary file after processing
os.remove(temp_file_path)
except Exception as e:
error_message = f"An error occurred: {e}"
logger.error(error_message)
return render_template("index.html", error=error_message)
else:
error_message = "Invalid file type. Please upload a valid audio file (MP3, MP4, WAV, M4A)."
logger.warning(error_message)
return render_template("index.html", error=error_message)
return render_template("index.html", sentiment=sentiment, error=error_message)
@app.errorhandler(500)
def internal_server_error(e):
"""Handles internal server errors."""
logger.error(f"Internal Server Error: {e}")
return render_template("error.html", error="Internal Server Error"), 500
if __name__ == "__main__":
app.run(debug=True)
Desglose del Código:
- Declaraciones de Importación: Importa los módulos necesarios de Flask, la biblioteca OpenAI,
os
,dotenv
,logging
, yOptional
yDict
para sugerencia de tipos. - Variables de Entorno: Carga la clave API de OpenAI desde el archivo
.env
. - Aplicación Flask: Crea una instancia de la aplicación Flask.
- Configuración de Registro: Configura el registro para la aplicación.
allowed_file
Función: Verifica si el archivo subido tiene una extensión de audio permitida (MP3, MP4, WAV, M4A).transcribe_audio
Función: Transcribe un archivo de audio usando la API Whisper de OpenAI. Registra la ruta del archivo y cualquier error durante la transcripción.analyze_sentiment
Función:def analyze_sentiment(text: str) -> Optional[str]:
: Define una función para analizar el sentimiento de un texto usando la API de Chat Completion de OpenAI.- Toma el texto transcrito como entrada.
- Envía una solicitud a la API de Chat Completion con un mensaje del sistema que instruye al modelo para realizar análisis de sentimiento. La temperatura se establece en 0.2 para hacer la salida más precisa, y
max_tokens
está limitado a 20 para mantener la respuesta concisa. - Extrae el sentimiento de la respuesta de la API.
- Registra el resultado del análisis de sentimiento.
- Incluye manejo de errores para errores de la API de OpenAI y otras excepciones.
index
Ruta:- Maneja solicitudes GET y POST.
- Para solicitudes GET, renderiza la página HTML inicial.
- Para solicitudes POST (cuando el usuario sube un archivo de audio):
- Valida el archivo subido.
- Guarda el archivo temporalmente.
- Llama a
transcribe_audio()
para transcribir el audio. - Llama a
analyze_sentiment()
para analizar el texto transcrito. - Renderiza la plantilla HTML, pasando el resultado del análisis de sentimiento o cualquier mensaje de error.
@app.errorhandler(500)
: Maneja errores internos del servidor registrando el error y renderizando una página de error amigable para el usuario.if __name__ == "__main__":
: Inicia el servidor de desarrollo Flask si el script se ejecuta directamente.
Paso 4: Crear la Plantilla HTML (templates/index.html)
Crea una carpeta llamada templates
en el mismo directorio que app.py
. Dentro de la carpeta templates
, crea un archivo llamado index.html
con el siguiente código HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audio Sentiment Analyzer</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
/* --- General Styles --- */
body {
font-family: 'Inter', sans-serif;
padding: 40px;
background-color: #f9fafb;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
color: #374151;
}
.container {
max-width: 800px;
width: 95%;
background-color: #fff;
padding: 2rem;
border-radius: 0.75rem;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05);
text-align: center;
}
h2 {
font-size: 2.25rem;
font-weight: 600;
margin-bottom: 1.5rem;
color: #1e293b;
}
p {
color: #6b7280;
margin-bottom: 1rem;
}
/* --- Form Styles --- */
form {
margin-top: 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
label {
font-size: 1rem;
font-weight: 600;
color: #4b5563;
margin-bottom: 0.25rem;
display: block;
text-align: left;
width: 100%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
input[type="file"] {
width: 100%;
max-width: 400px;
padding: 0.75rem;
border-radius: 0.5rem;
border: 1px solid #d1d5db;
font-size: 1rem;
margin-bottom: 0.25rem;
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
background-color: #4f46e5;
color: #fff;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s ease;
border: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
margin-top: 1rem;
}
input[type="submit"]:hover {
background-color: #4338ca;
}
input[type="submit"]:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3);
}
/* --- Result Styles --- */
.result-container {
margin-top: 2rem;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
background-color: #f8fafc;
}
.result-title{
font-size: 1.25rem;
font-weight: 600;
color: #1e293b;
margin-bottom: 0.75rem;
}
.sentiment-positive {
color: #16a34a;
font-weight: 600;
}
.sentiment-negative {
color: #dc2626;
font-weight: 600;
}
.sentiment-neutral {
color: #71717a;
font-weight: 600;
}
/* --- Error Styles --- */
.error-message {
color: #dc2626;
margin-top: 1rem;
padding: 0.75rem;
background-color: #fee2e2;
border-radius: 0.375rem;
border: 1px solid #fecaca;
text-align: center;
}
/* --- Responsive Adjustments --- */
@media (max-width: 768px) {
.container {
padding: 20px;
}
form {
gap: 1rem;
}
input[type="file"] {
max-width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h2>🎙️ Audio Sentiment Analyzer</h2>
<p> Upload an audio file to analyze the sentiment of the spoken content. Supported formats: MP3, MP4, WAV, M4A </p>
<form method="POST" enctype="multipart/form-data">
<label for="audio_file">Upload an audio file:</label><br>
<input type="file" name="audio_file" accept="audio/*" required><br><br>
<input type="submit" value="Analyze Sentiment">
</form>
{% if sentiment %}
<div class="result-container">
<h3 class = "result-title">Sentiment Analysis Result:</h3>
<p class="sentiment-{{ sentiment.lower() }}"> {{ sentiment }} </p>
</div>
{% endif %}
{% if error %}
<div class="error-message">{{ error }}</div>
{% endif %}
</div>
</body>
</html>
Elementos clave en la plantilla HTML:
- Estructura HTML:
- La sección
<head>
define el título, enlaza una hoja de estilos CSS y configura el viewport para que el diseño sea adaptable. - El
<body>
contiene el contenido visible, incluido un formulario para subir archivos de audio y una sección para mostrar el resultado del análisis de sentimiento.
- La sección
- Estilo CSS:
- Diseño moderno: El CSS ha sido actualizado con un diseño más actual.
- Diseño responsivo: El diseño se adapta mejor a pantallas pequeñas.
- Experiencia de usuario: Se ha mejorado el estilo de los formularios y los campos de entrada para facilitar su uso.
- Visualización clara de errores: Los mensajes de error están estilizados para que sean fácilmente visibles.ndicador de sentimiento: Los colores de los resultados cambian según el sentimiento detectado.
- Formulario:
- Se utiliza un
<form>
conenctype="multipart/form-data"
para gestionar la carga de archivos. - Un
<label>
y un<input type="file">
permiten al usuario seleccionar un archivo de audio. El atributoaccept="audio/*"
restringe la carga a archivos de audio. - Un botón
<input type="submit">
permite al usuario enviar el formulario.
- Se utiliza un
- Visualización del sentimiento:
- Se utiliza un
<div class="result-container">
para mostrar el resultado del análisis de sentimiento. El color del resultado cambia según el sentimiento detectado.
- Se utiliza un
- Manejo de errores:
- Se utiliza un
<div class="error-message">
para mostrar los mensajes de error al usuario.
- Se utiliza un
Pruébalo
- Guarda los archivos como
app.py
ytemplates/index.html
. - Asegúrate de tener tu clave de API de OpenAI en el archivo
.env
. - Ejecuta la aplicación:
python app.py
- Abre
http://localhost:5000
en tu navegador. - Sube un archivo de audio (por ejemplo, una grabación de voz o el archivo .mp3 de muestra).
- Visualiza el resultado del análisis de sentimiento mostrado en la página.
5.4 Análisis de Sentimiento de Audio con OpenAI
En esta sección, exploraremos cómo construir una aplicación web sofisticada en Flask que realiza análisis de sentimiento en contenido de audio utilizando las potentes APIs de OpenAI. Esta integración combina dos tecnologías clave: primero, la aplicación utiliza la API Whisper de OpenAI para convertir palabras habladas en texto escrito mediante una transcripción precisa. Luego, aprovecha los modelos de lenguaje de OpenAI para analizar el tono emocional y el sentimiento del contenido transcrito.
El flujo del proceso es sencillo pero potente: los usuarios suben un archivo de audio, que se transcribe a texto, y luego la aplicación aplica procesamiento de lenguaje natural para determinar si el mensaje del hablante transmite un sentimiento positivo, negativo o neutral. Este análisis de dos pasos proporciona información valiosa sobre el contenido emocional de las comunicaciones habladas, haciéndolo útil para varias aplicaciones como análisis de retroalimentación de clientes, investigación de mercado y moderación de contenido.
5.4.1 Lo que Construirás
La aplicación web proporciona una solución integral de análisis de audio con varias funcionalidades clave. Cuando los usuarios interactúan con la plataforma, realiza la siguiente secuencia de operaciones:
- Recepción y Procesamiento de Cargas de Audio: La aplicación cuenta con una interfaz web sofisticada que maneja cargas de archivos de audio con amplio soporte de formatos. Los usuarios pueden enviar archivos en formatos populares como MP3 (ideal para audio comprimido), WAV (perfecto para audio sin comprimir de alta calidad) y M4A (optimizado para grabaciones de voz). La interfaz incluye validación de archivos, verificación de tamaño y formato para asegurar un procesamiento fluido.
- Sistema Seguro de Gestión de Archivos: Al recibir una carga, la aplicación implementa un sistema robusto de almacenamiento temporal. Los archivos se almacenan en un directorio seguro con controles de acceso apropiados, utilizando protocolos automáticos de limpieza para prevenir el desbordamiento de almacenamiento. El sistema incluye mecanismos de manejo de errores para cargas fallidas, archivos corruptos y escenarios de tiempo de espera, asegurando una operación confiable incluso bajo carga pesada.
- Transcripción Avanzada de Audio: La integración con la API Whisper de OpenAI proporciona capacidades de reconocimiento de voz de última generación. Este modelo sofisticado sobresale en el manejo de varios acentos, dialectos y condiciones de ruido de fondo, entregando transcripciones precisas en múltiples idiomas. El sistema procesa el audio en fragmentos para un rendimiento óptimo e incluye seguimiento de progreso para archivos más largos.
- Análisis Integral de Sentimiento: La aplicación aprovecha el procesamiento avanzado de lenguaje natural de GPT-4 a través de la API de Chat Completion. Este análisis va más allá de la clasificación básica positivo/negativo, examinando pistas contextuales, matices emocionales y sutilezas lingüísticas. El sistema considera factores como el tono, la intensidad y el contexto semántico para proporcionar una comprensión matizada del sentimiento.
- Interfaz de Resultados Amigable: La aplicación presenta los resultados del análisis a través de una interfaz intuitiva y bien diseñada. Los usuarios reciben tanto la transcripción completa como un desglose detallado del sentimiento, con indicadores visuales claros para diferentes categorías emocionales. La interfaz incluye opciones para descargar resultados, compartir informes de análisis y ver análisis históricos cuando corresponda.
Esta revolucionaria combinación de tecnologías de transcripción de audio y análisis de lenguaje revoluciona cómo procesamos y entendemos el contenido hablado. Las aplicaciones abarcan múltiples industrias, ofreciendo perspectivas y mejoras de eficiencia sin precedentes:
- Análisis de retroalimentación de clientes desde grabaciones de voz - Esta aplicación transforma cómo las empresas manejan las interacciones con clientes. Los centros de llamadas y departamentos de servicio al cliente ahora pueden procesar automáticamente miles de llamadas para:
- Rastrear tendencias de satisfacción del cliente a lo largo del tiempo
- Identificar puntos específicos de dolor en las experiencias del cliente
- Generar perspectivas accionables para mejorar el servicio
- Entrenar representantes de servicio al cliente más efectivamente
- Detección de tonos emocionales en contenido hablado para análisis de medios - Esta capacidad proporciona a las empresas de medios herramientas sofisticadas para evaluación de contenido:
- Medir el compromiso emocional de la audiencia a lo largo del contenido
- Analizar la autenticidad y credibilidad del hablante
- Asegurar la consistencia del mensaje de marca a través de diferentes medios
- Optimizar el contenido para máximo impacto emocional
- Evaluación del sentimiento de contenido de audio en podcasts o entrevistas - Esta característica revoluciona el análisis de contenido al:
- Procesar horas de contenido en minutos
- Identificar momentos clave de significancia emocional
- Rastrear cambios de sentimiento a lo largo de las discusiones
- Permitir decisiones de estrategia de contenido basadas en datos
Tecnologías Utilizadas:
- Flask: Un marco de trabajo web de Python.
- API de OpenAI:
- Whisper para transcripción de audio.
- GPT-4 (o similar) para análisis de sentimiento.
- HTML: Para estructurar la página web.
- CSS: Para estilizar la página web.
Estructura del Proyecto:
El proyecto tendrá la siguiente estructura de archivos:
/audio_sentiment_analyzer
│
├── app.py
├── .env
└── templates/
└── index.html
app.py
: El archivo Python que contiene el código de la aplicación Flask..env
: Un archivo para almacenar la clave API de OpenAI.templates/
: Un directorio para almacenar las plantillas HTML.templates/index.html
: La plantilla HTML para la página principal.
5.4.2 Implementación Paso a Paso
Paso 1: Instalar Paquetes Requeridos
Descarga el archivo de audio de muestra: https://files.cuantum.tech/audio/someone-speaking.mp3
Instala las bibliotecas Python necesarias:
pip install flask openai python-dotenv
Paso 2: Configurar Variables de Entorno
Crea un archivo .env
en tu directorio del proyecto y añade tu clave API de OpenAI:
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
Paso 3: Crear la Aplicación Flask (app.py)
Crea un archivo Python llamado app.py
y añade el siguiente código:
from flask import Flask, request, render_template, jsonify
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional, Dict
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
app = Flask(__name__)
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ALLOWED_EXTENSIONS = {'mp3', 'mp4', 'wav', 'm4a'} # Allowed audio file extensions
def allowed_file(filename: str) -> bool:
"""
Checks if the uploaded file has an allowed extension.
Args:
filename (str): The name of the file.
Returns:
bool: True if the file has an allowed extension, False otherwise.
"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def transcribe_audio(file_path: str) -> Optional[str]:
"""
Transcribes an audio file using OpenAI's Whisper API.
Args:
file_path (str): The path to the audio file.
Returns:
Optional[str]: The transcribed text, or None on error.
"""
try:
logger.info(f"Transcribing audio file: {file_path}")
audio_file = open(file_path, "rb")
response = openai.Audio.transcriptions.create(
model="whisper-1",
file=audio_file,
)
transcript = response.text
logger.info(f"Transcription successful. Length: {len(transcript)} characters.")
return transcript
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during transcription: {e}")
return None
def analyze_sentiment(text: str) -> Optional[str]:
"""
Analyzes the sentiment of a given text using OpenAI's Chat Completion API.
Args:
text (str): The text to analyze.
Returns:
Optional[str]: The sentiment analysis result, or None on error.
"""
try:
logger.info("Analyzing sentiment of transcribed text.")
response = openai.chat.completions.create(
model="gpt-4", # Or another suitable chat model
messages=[
{
"role": "system",
"content": "You are a sentiment analysis expert. Provide a concise sentiment analysis of the text. Your response should be one of the following: 'Positive', 'Negative', or 'Neutral'.",
},
{"role": "user", "content": text},
],
temperature=0.2, # Keep the output focused
max_tokens=20
)
sentiment = response.choices[0].message.content
logger.info(f"Sentiment analysis result: {sentiment}")
return sentiment
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during sentiment analysis: {e}")
return None
@app.route("/", methods=["GET", "POST"])
def index():
"""
Handles the main route for the web application.
Allows users to upload an audio file, transcribes it, and analyzes the sentiment.
"""
sentiment = None
error_message = None
if request.method == "POST":
if 'audio_file' not in request.files:
error_message = "No file part"
logger.warning(error_message)
return render_template("index.html", error=error_message)
file = request.files['audio_file']
if file.filename == '':
error_message = "No file selected"
logger.warning(error_message)
return render_template("index.html", error=error_message)
if file and allowed_file(file.filename):
try:
# Securely save the uploaded file to a temporary location
temp_file_path = os.path.join(app.root_path, "temp_audio." + file.filename.rsplit('.', 1)[1].lower())
file.save(temp_file_path)
transcript = transcribe_audio(temp_file_path) # Transcribe the audio
if not transcript:
error_message = "Transcription failed. Please try again."
return render_template("index.html", error=error_message)
sentiment = analyze_sentiment(transcript)
if not sentiment:
error_message = "Sentiment analysis failed. Please try again."
return render_template("index.html", error=error_message)
# Optionally, delete the temporary file after processing
os.remove(temp_file_path)
except Exception as e:
error_message = f"An error occurred: {e}"
logger.error(error_message)
return render_template("index.html", error=error_message)
else:
error_message = "Invalid file type. Please upload a valid audio file (MP3, MP4, WAV, M4A)."
logger.warning(error_message)
return render_template("index.html", error=error_message)
return render_template("index.html", sentiment=sentiment, error=error_message)
@app.errorhandler(500)
def internal_server_error(e):
"""Handles internal server errors."""
logger.error(f"Internal Server Error: {e}")
return render_template("error.html", error="Internal Server Error"), 500
if __name__ == "__main__":
app.run(debug=True)
Desglose del Código:
- Declaraciones de Importación: Importa los módulos necesarios de Flask, la biblioteca OpenAI,
os
,dotenv
,logging
, yOptional
yDict
para sugerencia de tipos. - Variables de Entorno: Carga la clave API de OpenAI desde el archivo
.env
. - Aplicación Flask: Crea una instancia de la aplicación Flask.
- Configuración de Registro: Configura el registro para la aplicación.
allowed_file
Función: Verifica si el archivo subido tiene una extensión de audio permitida (MP3, MP4, WAV, M4A).transcribe_audio
Función: Transcribe un archivo de audio usando la API Whisper de OpenAI. Registra la ruta del archivo y cualquier error durante la transcripción.analyze_sentiment
Función:def analyze_sentiment(text: str) -> Optional[str]:
: Define una función para analizar el sentimiento de un texto usando la API de Chat Completion de OpenAI.- Toma el texto transcrito como entrada.
- Envía una solicitud a la API de Chat Completion con un mensaje del sistema que instruye al modelo para realizar análisis de sentimiento. La temperatura se establece en 0.2 para hacer la salida más precisa, y
max_tokens
está limitado a 20 para mantener la respuesta concisa. - Extrae el sentimiento de la respuesta de la API.
- Registra el resultado del análisis de sentimiento.
- Incluye manejo de errores para errores de la API de OpenAI y otras excepciones.
index
Ruta:- Maneja solicitudes GET y POST.
- Para solicitudes GET, renderiza la página HTML inicial.
- Para solicitudes POST (cuando el usuario sube un archivo de audio):
- Valida el archivo subido.
- Guarda el archivo temporalmente.
- Llama a
transcribe_audio()
para transcribir el audio. - Llama a
analyze_sentiment()
para analizar el texto transcrito. - Renderiza la plantilla HTML, pasando el resultado del análisis de sentimiento o cualquier mensaje de error.
@app.errorhandler(500)
: Maneja errores internos del servidor registrando el error y renderizando una página de error amigable para el usuario.if __name__ == "__main__":
: Inicia el servidor de desarrollo Flask si el script se ejecuta directamente.
Paso 4: Crear la Plantilla HTML (templates/index.html)
Crea una carpeta llamada templates
en el mismo directorio que app.py
. Dentro de la carpeta templates
, crea un archivo llamado index.html
con el siguiente código HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audio Sentiment Analyzer</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
/* --- General Styles --- */
body {
font-family: 'Inter', sans-serif;
padding: 40px;
background-color: #f9fafb;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
color: #374151;
}
.container {
max-width: 800px;
width: 95%;
background-color: #fff;
padding: 2rem;
border-radius: 0.75rem;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05);
text-align: center;
}
h2 {
font-size: 2.25rem;
font-weight: 600;
margin-bottom: 1.5rem;
color: #1e293b;
}
p {
color: #6b7280;
margin-bottom: 1rem;
}
/* --- Form Styles --- */
form {
margin-top: 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
label {
font-size: 1rem;
font-weight: 600;
color: #4b5563;
margin-bottom: 0.25rem;
display: block;
text-align: left;
width: 100%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
input[type="file"] {
width: 100%;
max-width: 400px;
padding: 0.75rem;
border-radius: 0.5rem;
border: 1px solid #d1d5db;
font-size: 1rem;
margin-bottom: 0.25rem;
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
background-color: #4f46e5;
color: #fff;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s ease;
border: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
margin-top: 1rem;
}
input[type="submit"]:hover {
background-color: #4338ca;
}
input[type="submit"]:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3);
}
/* --- Result Styles --- */
.result-container {
margin-top: 2rem;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
background-color: #f8fafc;
}
.result-title{
font-size: 1.25rem;
font-weight: 600;
color: #1e293b;
margin-bottom: 0.75rem;
}
.sentiment-positive {
color: #16a34a;
font-weight: 600;
}
.sentiment-negative {
color: #dc2626;
font-weight: 600;
}
.sentiment-neutral {
color: #71717a;
font-weight: 600;
}
/* --- Error Styles --- */
.error-message {
color: #dc2626;
margin-top: 1rem;
padding: 0.75rem;
background-color: #fee2e2;
border-radius: 0.375rem;
border: 1px solid #fecaca;
text-align: center;
}
/* --- Responsive Adjustments --- */
@media (max-width: 768px) {
.container {
padding: 20px;
}
form {
gap: 1rem;
}
input[type="file"] {
max-width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h2>🎙️ Audio Sentiment Analyzer</h2>
<p> Upload an audio file to analyze the sentiment of the spoken content. Supported formats: MP3, MP4, WAV, M4A </p>
<form method="POST" enctype="multipart/form-data">
<label for="audio_file">Upload an audio file:</label><br>
<input type="file" name="audio_file" accept="audio/*" required><br><br>
<input type="submit" value="Analyze Sentiment">
</form>
{% if sentiment %}
<div class="result-container">
<h3 class = "result-title">Sentiment Analysis Result:</h3>
<p class="sentiment-{{ sentiment.lower() }}"> {{ sentiment }} </p>
</div>
{% endif %}
{% if error %}
<div class="error-message">{{ error }}</div>
{% endif %}
</div>
</body>
</html>
Elementos clave en la plantilla HTML:
- Estructura HTML:
- La sección
<head>
define el título, enlaza una hoja de estilos CSS y configura el viewport para que el diseño sea adaptable. - El
<body>
contiene el contenido visible, incluido un formulario para subir archivos de audio y una sección para mostrar el resultado del análisis de sentimiento.
- La sección
- Estilo CSS:
- Diseño moderno: El CSS ha sido actualizado con un diseño más actual.
- Diseño responsivo: El diseño se adapta mejor a pantallas pequeñas.
- Experiencia de usuario: Se ha mejorado el estilo de los formularios y los campos de entrada para facilitar su uso.
- Visualización clara de errores: Los mensajes de error están estilizados para que sean fácilmente visibles.ndicador de sentimiento: Los colores de los resultados cambian según el sentimiento detectado.
- Formulario:
- Se utiliza un
<form>
conenctype="multipart/form-data"
para gestionar la carga de archivos. - Un
<label>
y un<input type="file">
permiten al usuario seleccionar un archivo de audio. El atributoaccept="audio/*"
restringe la carga a archivos de audio. - Un botón
<input type="submit">
permite al usuario enviar el formulario.
- Se utiliza un
- Visualización del sentimiento:
- Se utiliza un
<div class="result-container">
para mostrar el resultado del análisis de sentimiento. El color del resultado cambia según el sentimiento detectado.
- Se utiliza un
- Manejo de errores:
- Se utiliza un
<div class="error-message">
para mostrar los mensajes de error al usuario.
- Se utiliza un
Pruébalo
- Guarda los archivos como
app.py
ytemplates/index.html
. - Asegúrate de tener tu clave de API de OpenAI en el archivo
.env
. - Ejecuta la aplicación:
python app.py
- Abre
http://localhost:5000
en tu navegador. - Sube un archivo de audio (por ejemplo, una grabación de voz o el archivo .mp3 de muestra).
- Visualiza el resultado del análisis de sentimiento mostrado en la página.
5.4 Análisis de Sentimiento de Audio con OpenAI
En esta sección, exploraremos cómo construir una aplicación web sofisticada en Flask que realiza análisis de sentimiento en contenido de audio utilizando las potentes APIs de OpenAI. Esta integración combina dos tecnologías clave: primero, la aplicación utiliza la API Whisper de OpenAI para convertir palabras habladas en texto escrito mediante una transcripción precisa. Luego, aprovecha los modelos de lenguaje de OpenAI para analizar el tono emocional y el sentimiento del contenido transcrito.
El flujo del proceso es sencillo pero potente: los usuarios suben un archivo de audio, que se transcribe a texto, y luego la aplicación aplica procesamiento de lenguaje natural para determinar si el mensaje del hablante transmite un sentimiento positivo, negativo o neutral. Este análisis de dos pasos proporciona información valiosa sobre el contenido emocional de las comunicaciones habladas, haciéndolo útil para varias aplicaciones como análisis de retroalimentación de clientes, investigación de mercado y moderación de contenido.
5.4.1 Lo que Construirás
La aplicación web proporciona una solución integral de análisis de audio con varias funcionalidades clave. Cuando los usuarios interactúan con la plataforma, realiza la siguiente secuencia de operaciones:
- Recepción y Procesamiento de Cargas de Audio: La aplicación cuenta con una interfaz web sofisticada que maneja cargas de archivos de audio con amplio soporte de formatos. Los usuarios pueden enviar archivos en formatos populares como MP3 (ideal para audio comprimido), WAV (perfecto para audio sin comprimir de alta calidad) y M4A (optimizado para grabaciones de voz). La interfaz incluye validación de archivos, verificación de tamaño y formato para asegurar un procesamiento fluido.
- Sistema Seguro de Gestión de Archivos: Al recibir una carga, la aplicación implementa un sistema robusto de almacenamiento temporal. Los archivos se almacenan en un directorio seguro con controles de acceso apropiados, utilizando protocolos automáticos de limpieza para prevenir el desbordamiento de almacenamiento. El sistema incluye mecanismos de manejo de errores para cargas fallidas, archivos corruptos y escenarios de tiempo de espera, asegurando una operación confiable incluso bajo carga pesada.
- Transcripción Avanzada de Audio: La integración con la API Whisper de OpenAI proporciona capacidades de reconocimiento de voz de última generación. Este modelo sofisticado sobresale en el manejo de varios acentos, dialectos y condiciones de ruido de fondo, entregando transcripciones precisas en múltiples idiomas. El sistema procesa el audio en fragmentos para un rendimiento óptimo e incluye seguimiento de progreso para archivos más largos.
- Análisis Integral de Sentimiento: La aplicación aprovecha el procesamiento avanzado de lenguaje natural de GPT-4 a través de la API de Chat Completion. Este análisis va más allá de la clasificación básica positivo/negativo, examinando pistas contextuales, matices emocionales y sutilezas lingüísticas. El sistema considera factores como el tono, la intensidad y el contexto semántico para proporcionar una comprensión matizada del sentimiento.
- Interfaz de Resultados Amigable: La aplicación presenta los resultados del análisis a través de una interfaz intuitiva y bien diseñada. Los usuarios reciben tanto la transcripción completa como un desglose detallado del sentimiento, con indicadores visuales claros para diferentes categorías emocionales. La interfaz incluye opciones para descargar resultados, compartir informes de análisis y ver análisis históricos cuando corresponda.
Esta revolucionaria combinación de tecnologías de transcripción de audio y análisis de lenguaje revoluciona cómo procesamos y entendemos el contenido hablado. Las aplicaciones abarcan múltiples industrias, ofreciendo perspectivas y mejoras de eficiencia sin precedentes:
- Análisis de retroalimentación de clientes desde grabaciones de voz - Esta aplicación transforma cómo las empresas manejan las interacciones con clientes. Los centros de llamadas y departamentos de servicio al cliente ahora pueden procesar automáticamente miles de llamadas para:
- Rastrear tendencias de satisfacción del cliente a lo largo del tiempo
- Identificar puntos específicos de dolor en las experiencias del cliente
- Generar perspectivas accionables para mejorar el servicio
- Entrenar representantes de servicio al cliente más efectivamente
- Detección de tonos emocionales en contenido hablado para análisis de medios - Esta capacidad proporciona a las empresas de medios herramientas sofisticadas para evaluación de contenido:
- Medir el compromiso emocional de la audiencia a lo largo del contenido
- Analizar la autenticidad y credibilidad del hablante
- Asegurar la consistencia del mensaje de marca a través de diferentes medios
- Optimizar el contenido para máximo impacto emocional
- Evaluación del sentimiento de contenido de audio en podcasts o entrevistas - Esta característica revoluciona el análisis de contenido al:
- Procesar horas de contenido en minutos
- Identificar momentos clave de significancia emocional
- Rastrear cambios de sentimiento a lo largo de las discusiones
- Permitir decisiones de estrategia de contenido basadas en datos
Tecnologías Utilizadas:
- Flask: Un marco de trabajo web de Python.
- API de OpenAI:
- Whisper para transcripción de audio.
- GPT-4 (o similar) para análisis de sentimiento.
- HTML: Para estructurar la página web.
- CSS: Para estilizar la página web.
Estructura del Proyecto:
El proyecto tendrá la siguiente estructura de archivos:
/audio_sentiment_analyzer
│
├── app.py
├── .env
└── templates/
└── index.html
app.py
: El archivo Python que contiene el código de la aplicación Flask..env
: Un archivo para almacenar la clave API de OpenAI.templates/
: Un directorio para almacenar las plantillas HTML.templates/index.html
: La plantilla HTML para la página principal.
5.4.2 Implementación Paso a Paso
Paso 1: Instalar Paquetes Requeridos
Descarga el archivo de audio de muestra: https://files.cuantum.tech/audio/someone-speaking.mp3
Instala las bibliotecas Python necesarias:
pip install flask openai python-dotenv
Paso 2: Configurar Variables de Entorno
Crea un archivo .env
en tu directorio del proyecto y añade tu clave API de OpenAI:
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
Paso 3: Crear la Aplicación Flask (app.py)
Crea un archivo Python llamado app.py
y añade el siguiente código:
from flask import Flask, request, render_template, jsonify
import openai
import os
from dotenv import load_dotenv
import logging
from typing import Optional, Dict
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
app = Flask(__name__)
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
ALLOWED_EXTENSIONS = {'mp3', 'mp4', 'wav', 'm4a'} # Allowed audio file extensions
def allowed_file(filename: str) -> bool:
"""
Checks if the uploaded file has an allowed extension.
Args:
filename (str): The name of the file.
Returns:
bool: True if the file has an allowed extension, False otherwise.
"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def transcribe_audio(file_path: str) -> Optional[str]:
"""
Transcribes an audio file using OpenAI's Whisper API.
Args:
file_path (str): The path to the audio file.
Returns:
Optional[str]: The transcribed text, or None on error.
"""
try:
logger.info(f"Transcribing audio file: {file_path}")
audio_file = open(file_path, "rb")
response = openai.Audio.transcriptions.create(
model="whisper-1",
file=audio_file,
)
transcript = response.text
logger.info(f"Transcription successful. Length: {len(transcript)} characters.")
return transcript
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during transcription: {e}")
return None
def analyze_sentiment(text: str) -> Optional[str]:
"""
Analyzes the sentiment of a given text using OpenAI's Chat Completion API.
Args:
text (str): The text to analyze.
Returns:
Optional[str]: The sentiment analysis result, or None on error.
"""
try:
logger.info("Analyzing sentiment of transcribed text.")
response = openai.chat.completions.create(
model="gpt-4", # Or another suitable chat model
messages=[
{
"role": "system",
"content": "You are a sentiment analysis expert. Provide a concise sentiment analysis of the text. Your response should be one of the following: 'Positive', 'Negative', or 'Neutral'.",
},
{"role": "user", "content": text},
],
temperature=0.2, # Keep the output focused
max_tokens=20
)
sentiment = response.choices[0].message.content
logger.info(f"Sentiment analysis result: {sentiment}")
return sentiment
except openai.error.OpenAIError as e:
logger.error(f"OpenAI API Error: {e}")
return None
except Exception as e:
logger.error(f"Error during sentiment analysis: {e}")
return None
@app.route("/", methods=["GET", "POST"])
def index():
"""
Handles the main route for the web application.
Allows users to upload an audio file, transcribes it, and analyzes the sentiment.
"""
sentiment = None
error_message = None
if request.method == "POST":
if 'audio_file' not in request.files:
error_message = "No file part"
logger.warning(error_message)
return render_template("index.html", error=error_message)
file = request.files['audio_file']
if file.filename == '':
error_message = "No file selected"
logger.warning(error_message)
return render_template("index.html", error=error_message)
if file and allowed_file(file.filename):
try:
# Securely save the uploaded file to a temporary location
temp_file_path = os.path.join(app.root_path, "temp_audio." + file.filename.rsplit('.', 1)[1].lower())
file.save(temp_file_path)
transcript = transcribe_audio(temp_file_path) # Transcribe the audio
if not transcript:
error_message = "Transcription failed. Please try again."
return render_template("index.html", error=error_message)
sentiment = analyze_sentiment(transcript)
if not sentiment:
error_message = "Sentiment analysis failed. Please try again."
return render_template("index.html", error=error_message)
# Optionally, delete the temporary file after processing
os.remove(temp_file_path)
except Exception as e:
error_message = f"An error occurred: {e}"
logger.error(error_message)
return render_template("index.html", error=error_message)
else:
error_message = "Invalid file type. Please upload a valid audio file (MP3, MP4, WAV, M4A)."
logger.warning(error_message)
return render_template("index.html", error=error_message)
return render_template("index.html", sentiment=sentiment, error=error_message)
@app.errorhandler(500)
def internal_server_error(e):
"""Handles internal server errors."""
logger.error(f"Internal Server Error: {e}")
return render_template("error.html", error="Internal Server Error"), 500
if __name__ == "__main__":
app.run(debug=True)
Desglose del Código:
- Declaraciones de Importación: Importa los módulos necesarios de Flask, la biblioteca OpenAI,
os
,dotenv
,logging
, yOptional
yDict
para sugerencia de tipos. - Variables de Entorno: Carga la clave API de OpenAI desde el archivo
.env
. - Aplicación Flask: Crea una instancia de la aplicación Flask.
- Configuración de Registro: Configura el registro para la aplicación.
allowed_file
Función: Verifica si el archivo subido tiene una extensión de audio permitida (MP3, MP4, WAV, M4A).transcribe_audio
Función: Transcribe un archivo de audio usando la API Whisper de OpenAI. Registra la ruta del archivo y cualquier error durante la transcripción.analyze_sentiment
Función:def analyze_sentiment(text: str) -> Optional[str]:
: Define una función para analizar el sentimiento de un texto usando la API de Chat Completion de OpenAI.- Toma el texto transcrito como entrada.
- Envía una solicitud a la API de Chat Completion con un mensaje del sistema que instruye al modelo para realizar análisis de sentimiento. La temperatura se establece en 0.2 para hacer la salida más precisa, y
max_tokens
está limitado a 20 para mantener la respuesta concisa. - Extrae el sentimiento de la respuesta de la API.
- Registra el resultado del análisis de sentimiento.
- Incluye manejo de errores para errores de la API de OpenAI y otras excepciones.
index
Ruta:- Maneja solicitudes GET y POST.
- Para solicitudes GET, renderiza la página HTML inicial.
- Para solicitudes POST (cuando el usuario sube un archivo de audio):
- Valida el archivo subido.
- Guarda el archivo temporalmente.
- Llama a
transcribe_audio()
para transcribir el audio. - Llama a
analyze_sentiment()
para analizar el texto transcrito. - Renderiza la plantilla HTML, pasando el resultado del análisis de sentimiento o cualquier mensaje de error.
@app.errorhandler(500)
: Maneja errores internos del servidor registrando el error y renderizando una página de error amigable para el usuario.if __name__ == "__main__":
: Inicia el servidor de desarrollo Flask si el script se ejecuta directamente.
Paso 4: Crear la Plantilla HTML (templates/index.html)
Crea una carpeta llamada templates
en el mismo directorio que app.py
. Dentro de la carpeta templates
, crea un archivo llamado index.html
con el siguiente código HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audio Sentiment Analyzer</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
/* --- General Styles --- */
body {
font-family: 'Inter', sans-serif;
padding: 40px;
background-color: #f9fafb;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
color: #374151;
}
.container {
max-width: 800px;
width: 95%;
background-color: #fff;
padding: 2rem;
border-radius: 0.75rem;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.05);
text-align: center;
}
h2 {
font-size: 2.25rem;
font-weight: 600;
margin-bottom: 1.5rem;
color: #1e293b;
}
p {
color: #6b7280;
margin-bottom: 1rem;
}
/* --- Form Styles --- */
form {
margin-top: 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
}
label {
font-size: 1rem;
font-weight: 600;
color: #4b5563;
margin-bottom: 0.25rem;
display: block;
text-align: left;
width: 100%;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
input[type="file"] {
width: 100%;
max-width: 400px;
padding: 0.75rem;
border-radius: 0.5rem;
border: 1px solid #d1d5db;
font-size: 1rem;
margin-bottom: 0.25rem;
margin-left: auto;
margin-right: auto;
}
input[type="submit"] {
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
background-color: #4f46e5;
color: #fff;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s ease;
border: none;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
margin-top: 1rem;
}
input[type="submit"]:hover {
background-color: #4338ca;
}
input[type="submit"]:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3);
}
/* --- Result Styles --- */
.result-container {
margin-top: 2rem;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1rem;
background-color: #f8fafc;
}
.result-title{
font-size: 1.25rem;
font-weight: 600;
color: #1e293b;
margin-bottom: 0.75rem;
}
.sentiment-positive {
color: #16a34a;
font-weight: 600;
}
.sentiment-negative {
color: #dc2626;
font-weight: 600;
}
.sentiment-neutral {
color: #71717a;
font-weight: 600;
}
/* --- Error Styles --- */
.error-message {
color: #dc2626;
margin-top: 1rem;
padding: 0.75rem;
background-color: #fee2e2;
border-radius: 0.375rem;
border: 1px solid #fecaca;
text-align: center;
}
/* --- Responsive Adjustments --- */
@media (max-width: 768px) {
.container {
padding: 20px;
}
form {
gap: 1rem;
}
input[type="file"] {
max-width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<h2>🎙️ Audio Sentiment Analyzer</h2>
<p> Upload an audio file to analyze the sentiment of the spoken content. Supported formats: MP3, MP4, WAV, M4A </p>
<form method="POST" enctype="multipart/form-data">
<label for="audio_file">Upload an audio file:</label><br>
<input type="file" name="audio_file" accept="audio/*" required><br><br>
<input type="submit" value="Analyze Sentiment">
</form>
{% if sentiment %}
<div class="result-container">
<h3 class = "result-title">Sentiment Analysis Result:</h3>
<p class="sentiment-{{ sentiment.lower() }}"> {{ sentiment }} </p>
</div>
{% endif %}
{% if error %}
<div class="error-message">{{ error }}</div>
{% endif %}
</div>
</body>
</html>
Elementos clave en la plantilla HTML:
- Estructura HTML:
- La sección
<head>
define el título, enlaza una hoja de estilos CSS y configura el viewport para que el diseño sea adaptable. - El
<body>
contiene el contenido visible, incluido un formulario para subir archivos de audio y una sección para mostrar el resultado del análisis de sentimiento.
- La sección
- Estilo CSS:
- Diseño moderno: El CSS ha sido actualizado con un diseño más actual.
- Diseño responsivo: El diseño se adapta mejor a pantallas pequeñas.
- Experiencia de usuario: Se ha mejorado el estilo de los formularios y los campos de entrada para facilitar su uso.
- Visualización clara de errores: Los mensajes de error están estilizados para que sean fácilmente visibles.ndicador de sentimiento: Los colores de los resultados cambian según el sentimiento detectado.
- Formulario:
- Se utiliza un
<form>
conenctype="multipart/form-data"
para gestionar la carga de archivos. - Un
<label>
y un<input type="file">
permiten al usuario seleccionar un archivo de audio. El atributoaccept="audio/*"
restringe la carga a archivos de audio. - Un botón
<input type="submit">
permite al usuario enviar el formulario.
- Se utiliza un
- Visualización del sentimiento:
- Se utiliza un
<div class="result-container">
para mostrar el resultado del análisis de sentimiento. El color del resultado cambia según el sentimiento detectado.
- Se utiliza un
- Manejo de errores:
- Se utiliza un
<div class="error-message">
para mostrar los mensajes de error al usuario.
- Se utiliza un
Pruébalo
- Guarda los archivos como
app.py
ytemplates/index.html
. - Asegúrate de tener tu clave de API de OpenAI en el archivo
.env
. - Ejecuta la aplicación:
python app.py
- Abre
http://localhost:5000
en tu navegador. - Sube un archivo de audio (por ejemplo, una grabación de voz o el archivo .mp3 de muestra).
- Visualiza el resultado del análisis de sentimiento mostrado en la página.