Proyecto: SENTIMENT API — Análisis Inteligente de Feedback de Clientes
Equipo: H12-25-L-Equipo 63
Período: Diciembre 2025 – Enero 2026
Esta documentación describe el contrato de la API REST para el análisis de sentimiento de comentarios de clientes.
Base URL:
- Desarrollo:
http://localhost:8080(endpoints bajo/v1) - Producción: (Pendiente de despliegue)
Formato: JSON
Idioma de entrada: Multilenguaje
Idioma de análisis en DS: Inglés (requerido)
Según las especificaciones del cliente (NoCountry), el formato JSON de entrada y salida DEBE cumplir estrictamente con el siguiente contrato:
Entrada:
{"text": "..."}Salida:
{
"prevision": "Positivo",
"probabilidad": 0.87,
"textoTraducido": "The service was excellent and very helpful",
"palabrasClave": ["excellent", "helpful", "service"]
}Campos requeridos en la respuesta:
prevision(String): Clasificación del sentimiento. Valores:"Positivo"o"Negativo"probabilidad(Number): Probabilidad del resultado entre 0 y 1
Requerimiento: La API DEBE implementar este formato exacto. No se aceptan variaciones como sentiment/probability u otros formatos alternativos. El contrato debe cumplirse tal como lo exige el cliente.
Versión actual (MVP): No requiere autenticación
Analiza el sentimiento de un texto y devuelve la clasificación con su probabilidad asociada.
Método: POST
Ruta: /v1/sentiment
Content-Type: application/json
Body:
{
"text": "The service was excellent and very helpful"
}Campos:
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
text |
String | Sí | Texto a analizar (cualquier idioma). Se traducirá automáticamente al inglés para análisis |
{
"prevision": "Positivo",
"probabilidad": 0.87,
"textoTraducido": "The service was excellent and very helpful",
"palabrasClave": ["excellent", "helpful", "service"]
}Campos de respuesta (Obligatorios):
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
prevision |
String | Sí | Clasificación del sentimiento. Valores posibles: "Positivo" o "Negativo" |
probabilidad |
Number | Sí | Probabilidad del resultado. Valor entre 0 y 1 (inclusive) |
textoTraducido |
String | No | Texto traducido al inglés usado para el análisis (si se envió en otro idioma) |
palabrasClave |
Array | No | Palabras clave más influyentes en la predicción (explicabilidad del modelo) |
Requerimiento del cliente: Este formato DEBE ser implementado exactamente como se especifica. La API debe devolver prevision y probabilidad (en español) según las especificaciones de NoCountry.
Ejemplo de respuesta positiva:
{
"prevision": "Positivo",
"probabilidad": 0.92
}Ejemplo de respuesta negativa:
{
"prevision": "Negativo",
"probabilidad": 0.85
}Analiza múltiples textos en una sola petición y devuelve resultados por cada elemento.
Método: POST
Ruta: /v1/sentiment/batch
Content-Type: application/json
Body:
{
"texts": [
"The product is excellent and the service is great",
"I am disappointed with the delivery time"
]
}{
"total": 2,
"results": [
{
"prevision": "Positivo",
"probabilidad": 0.93,
"textoTraducido": "The product is excellent and the service is great",
"palabrasClave": ["excellent", "service", "great"]
},
{
"prevision": "Negativo",
"probabilidad": 0.88,
"textoTraducido": "I am disappointed with the delivery time",
"palabrasClave": ["disappointed", "delivery", "time"]
}
]
}Devuelve métricas agregadas para el dashboard (conteos y porcentajes).
Método: GET
Ruta: /v1/stats
Response - Éxito (200 OK):
{
"total_analizados": 120,
"positivos": 80,
"negativos": 40,
"porcentaje_positivos": "67%",
"porcentaje_negativos": "33%",
"top_words_pos": {"great": 10, "excellent": 8},
"top_words_neg": {"bad": 6, "late": 5}
}Entrega un resumen técnico de totales y promedio de confianza del sistema.
Método: GET
Ruta: /v1/analytics
Response - Éxito (200 OK):
{
"totalAnalisis": 120,
"positivos": 80,
"negativos": 40,
"promedioConfianza": 0.86
}Obtiene registros y métricas agregadas por rango de fechas, con paginación y filtro opcional por sentimiento.
Método: GET
Ruta: /v1/analytics/range
Query Params:
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
startDate |
String | Sí | Fecha inicial (dd-MM-yyyy) |
endDate |
String | Sí | Fecha final (dd-MM-yyyy) |
sentiment |
String | No | Positivo o Negativo |
page |
Number | No | Página (0-based). Default: 0 |
size |
Number | No | Tamaño de página. Default: 15 |
Response - Éxito (200 OK):
{
"desde": "01-01-2026",
"hasta": "31-01-2026",
"total": 120,
"positivos": 80,
"negativos": 40,
"porcentajePositivos": "67%",
"porcentajeNegativos": "33%",
"topWordsPos": {"great": 10, "excellent": 8},
"topWordsNeg": {"bad": 6, "late": 5},
"registros": [
{
"fecha": "15-01-2026",
"textoOriginal": "The service was excellent",
"textoInterpretado": "The service was excellent",
"prevision": "Positivo",
"probabilidad": 0.92,
"palabrasClave": ["excellent", "service"]
}
],
"page": 0,
"size": 15,
"totalPages": 8
}Exporta el historial filtrado en formato CSV.
Método: GET
Ruta: /v1/analytics/range/export
Query Params: mismos que /v1/analytics/range (sin paginación)
El campo text debe cumplir con las siguientes reglas:
- Campo obligatorio: El campo
textes requerido y no puede estar ausente - No vacío: El campo
textno puede ser una cadena vacía ("") - Longitud mínima: El texto debe tener al menos 10 caracteres
- Longitud máxima: El texto debe tener como máximo 500 caracteres (configurable)
- Caracteres permitidos: El sistema puede restringir caracteres no válidos según acuerdos del equipo
Las validaciones se aplican con Bean Validation (anotaciones en DTOs) usando
@NotBlank y @Size. Si alguna validación falla, se detiene el proceso y se
devuelve un error inmediatamente.
La API devuelve errores en un formato uniforme para facilitar el manejo desde el frontend.
Todos los errores siguen el siguiente formato estandarizado:
{
"timestamp": "2025-01-15T10:30:00",
"status": 400,
"error": "Bad Request",
"message": "Descripción clara del problema en español",
"path": "/v1/sentiment",
"details": {
"text": "El campo 'text' es obligatorio"
}
}Campos:
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
timestamp |
String (ISO 8601) | Sí | Fecha y hora en que ocurrió el error |
status |
Number | Sí | Código de estado HTTP |
error |
String | Sí | Tipo de error (nombre del estado HTTP) |
message |
String | Sí | Mensaje descriptivo del error en español |
path |
String | Sí | Ruta del endpoint donde ocurrió el error |
details |
Object | No | Detalles adicionales del error. Presente en errores de validación con mapeo campo → mensaje |
| Código | Significado | Cuándo se usa |
|---|---|---|
200 |
OK | Request exitoso, análisis completado |
400 |
Bad Request | Error de validación (campo faltante, formato incorrecto, longitud inválida, etc.) |
500 |
Internal Server Error | Error interno del servidor (fallo en integración con DS, error inesperado, etc.) |
503 |
Service Unavailable | Servicio de Data Science no disponible (opcional) |
Request:
{}Response (400 Bad Request):
{
"timestamp": "2025-01-15T10:30:00",
"status": 400,
"error": "Bad Request",
"message": "Error de validación en los datos de entrada",
"path": "/v1/sentiment",
"details": {
"text": "El campo 'text' es obligatorio"
}
}Request:
{
"text": ""
}Response (400 Bad Request):
{
"timestamp": "2025-01-15T10:30:00",
"status": 400,
"error": "Bad Request",
"message": "Error de validación en los datos de entrada",
"path": "/v1/sentiment",
"details": {
"text": "El campo 'text' no puede estar vacío"
}
}Request:
{
"text": "short"
}Response (400 Bad Request):
{
"timestamp": "2025-01-15T10:30:00",
"status": 400,
"error": "Bad Request",
"message": "Error de validación en los datos de entrada",
"path": "/v1/sentiment",
"details": {
"text": "El campo 'text' debe tener al menos 10 caracteres"
}
}Request:
{
"text": "Este es un texto muy largo que excede el límite máximo permitido de caracteres para el análisis de sentimiento..."
}Response (400 Bad Request):
{
"timestamp": "2025-01-15T10:30:00",
"status": 400,
"error": "Bad Request",
"message": "Error de validación en los datos de entrada",
"path": "/v1/sentiment",
"details": {
"text": "El campo 'text' no puede exceder 500 caracteres"
}
}Response (500 Internal Server Error):
{
"timestamp": "2025-01-15T10:30:00",
"status": 500,
"error": "Internal Server Error",
"message": "Error interno del servidor",
"path": "/v1/sentiment"
}Response (503 Service Unavailable):
{
"timestamp": "2025-01-15T10:30:00",
"status": 503,
"error": "Service Unavailable",
"message": "El servicio de análisis de sentimiento no está disponible en este momento. Por favor, intenta más tarde.",
"path": "/v1/sentiment"
}La API implementa manejo centralizado de errores mediante @RestControllerAdvice en Spring Boot (GlobalExceptionHandler).
Handlers implementados:
| Excepción | Código HTTP | Cuándo se activa |
|---|---|---|
MethodArgumentNotValidException |
400 | Errores de validación en DTOs con @Valid (campos faltantes, longitud, formato) |
ConstraintViolationException |
400 | Violaciones de restricciones en parámetros de URL/path |
HttpMessageNotReadableException |
400 | JSON mal formado o no deserializable |
ServiceUnavailableException |
503 | Servicio de Data Science no disponible |
Exception (genérico) |
500 | Cualquier error no capturado por handlers específicos |
Características:
- Formato uniforme de errores con
ApiErrorResponse - Detalles de validación por campo en el objeto
details - Logging de errores para debugging
- Mensajes en español para facilitar comprensión
- No expone detalles internos del sistema al cliente (seguridad)
Request exitoso:
curl -X POST http://localhost:8080/v1/sentiment \
-H "Content-Type: application/json" \
-d '{"text": "The product quality is outstanding and the customer service is excellent"}'Response:
{
"prevision": "Positivo",
"probabilidad": 0.94
}Request con error:
curl -X POST http://localhost:8080/v1/sentiment \
-H "Content-Type: application/json" \
-d '{"text": "short"}'Response:
{
"timestamp": "2025-01-15T10:30:00",
"status": 400,
"error": "Bad Request",
"message": "Error de validación en los datos de entrada",
"path": "/v1/sentiment",
"details": {
"text": "El campo 'text' debe tener al menos 10 caracteres"
}
}- Método: POST
- URL:
http://localhost:8080/v1/sentiment - Headers:
Content-Type: application/json
- Body (raw JSON):
{
"text": "I am very disappointed with the product quality"
}- Response esperado:
{
"prevision": "Negativo",
"probabilidad": 0.89
}- Entrada aceptada: Multilenguaje (cualquier idioma)
- Procesamiento interno: El servicio de Data Science traduce automáticamente el texto al inglés (mediante código) antes de enviarlo al modelo de Machine Learning
- Validación: No se valida el idioma de entrada. El backend acepta cualquier texto y delega la traducción al servicio de Data Science
- Razón: El modelo de Data Science está entrenado exclusivamente con datos en inglés, por lo que la traducción automática garantiza que todos los textos puedan ser analizados correctamente
- Campo de respuesta: Si el texto fue traducido, la API retorna el campo opcional
textoTraducidocon la versión en inglés usada para el análisis
Todas las respuestas exitosas siguen el formato especificado en la sección 2.1, cumpliendo con el contrato obligatorio del cliente (NoCountry).
- La API mantiene un formato consistente para errores para que el dashboard pueda mostrar mensajes claros
- Los mensajes de error están en español para facilitar la comprensión
- Los códigos de estado HTTP siguen las convenciones estándar
La API almacena todos los análisis realizados en una base de datos PostgreSQL con los siguientes campos:
- ID único del análisis
- Texto analizado (original)
- Texto traducido (si aplica)
- Palabras clave detectadas (
palabrasClave) - Resultado de la predicción (prevision)
- Probabilidad
- Timestamp de creación
Nota: Los datos almacenados pueden consultarse mediante endpoints de Analytics (ver sección 2.3).
Esta documentación está escrita en Markdown para facilitar el desarrollo del MVP. En futuras iteraciones, la documentación migrará a OpenAPI/Swagger para:
- Generación automática de clientes SDK
- Interfaz interactiva de pruebas (Swagger UI)
- Validación automática de contratos
- Mejor integración con herramientas de CI/CD (En un futuro)
La estructura actual facilita esta transición, ya que toda la información necesaria está documentada y puede mapearse directamente a un spec OpenAPI.
Versión actual: 1.0.0 (/v1/sentiment).