# Smart Task API
Una API REST construida con FastAPI para gestionar tareas con sistema de prioridades inteligente.
## Características
- Gestión completa de usuarios y tareas
- Sistema de categorías personalizadas
- Base de datos PostgreSQL
- API documentada automáticamente con Swagger UI
- Arquitectura escalable y mantenible
## Prerrequisitos
- Python 3.11+
- PostgreSQL 12+
- Git
## Instalación y Configuración
### 1. Clonar el repositorio
```bash
git clone https://github.com/AndyCG03/backend-smart-task# Crear entorno virtual
python -m venv venv
# Activar entorno virtual
# Windows:
venv\Scripts\activate
# Linux/Mac:
source venv/bin/activatepip install -r requirements.txtOpción A: Usar PostgreSQL local
- Instalar PostgreSQL
- Crear base de datos:
CREATE DATABASE smart_task;Crear Usuario Administrador
El sistema incluye un script para crear usuarios administradores:
# Ejecutar el script de creación de administrador
python scripts/admin_init.py
### 5. Configurar variables de entorno
Crear archivo `.env` en la raíz del proyecto:
```env
# Database
DATABASE_URL=postgresql://postgres:password@localhost:5432/smart_task
# CORS
ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
# App
DEBUG=trueuvicorn app.main:app --reload --host 0.0.0.0 --port 8000app/
├── main.py # Punto de entrada de la aplicación
├── config.py # Configuración y variables de entorno
├── database.py # Conexión a la base de datos
├── models/
│ ├── database_models.py # Modelos de SQLAlchemy
│ └── pydantic_models.py # Schemas Pydantic para validación
└── api/
├── routes.py # Router principal
└── endpoints/ # Endpoints de la API
├── users.py # Gestión de usuarios
├── tasks.py # Gestión de tareas
├── categories.py # Gestión de categorías
├── recommendations.py # Recomendaciones diarias
├── energy_logs.py # Registros de energía
└── task_history.py # Historial de tareas
- users: Gestión de usuarios y preferencias
- tasks: Tareas con sistema de prioridad
- categories: Categorías personalizadas por usuario
- daily_recommendations: Recomendaciones diarias
- energy_logs: Registros de niveles de energía
- task_history: Historial de cambios en tareas
GET /api/v1/users/- Listar usuariosGET /api/v1/users/{user_id}- Obtener usuario específicoPOST /api/v1/users/- Crear usuarioPUT /api/v1/users/{user_id}- Actualizar usuario
GET /api/v1/tasks/- Listar tareasGET /api/v1/tasks/{task_id}- Obtener tarea específicaPOST /api/v1/tasks/- Crear tareaPUT /api/v1/tasks/{task_id}- Actualizar tareaDELETE /api/v1/tasks/{task_id}- Eliminar tarea
GET /api/v1/categories/- Listar categorías de usuarioGET /api/v1/categories/{category_id}- Obtener categoría específicaPOST /api/v1/categories/- Crear categoríaPUT /api/v1/categories/{category_id}- Actualizar categoríaDELETE /api/v1/categories/{category_id}- Eliminar categoría
GET /api/v1/recommendations/- Listar recomendacionesGET /api/v1/recommendations/{recommendation_id}- Obtener recomendación específicaPOST /api/v1/recommendations/- Crear recomendaciónPUT /api/v1/recommendations/{recommendation_id}- Actualizar recomendaciónPUT /api/v1/recommendations/{recommendation_id}/status- Actualizar estado
GET /api/v1/energy-logs/- Listar registros de energíaGET /api/v1/energy-logs/{log_id}- Obtener registro específicoPOST /api/v1/energy-logs/- Crear registroPUT /api/v1/energy-logs/{log_id}- Actualizar registroDELETE /api/v1/energy-logs/{log_id}- Eliminar registro
GET /api/v1/task-history/task/{task_id}- Historial de una tareaGET /api/v1/task-history/user/{user_id}- Historial de usuarioGET /api/v1/task-history/{history_id}- Entrada específica de historial
Una vez ejecutada la aplicación, la documentación automática estará disponible en:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
curl -X POST "http://localhost:8000/api/v1/users/" \
-H "Content-Type: application/json" \
-d '{
"email": "usuario@ejemplo.com",
"name": "Juan Pérez",
"password": "password123",
"energy_level": "medium"
}'curl -X POST "http://localhost:8000/api/v1/tasks/" \
-H "Content-Type: application/json" \
-d '{
"title": "Completar documentación",
"description": "Terminar el README del proyecto",
"urgency": "high",
"impact": "high",
"estimated_duration": 120,
"user_id": "uuid-del-usuario"
}'El sistema incorpora un modelo de Machine Learning para la priorización inteligente de tareas y recomendaciones personalizadas, con capacidad de aprendizaje continuo y adaptación contextual en tiempo real. El diseño prioriza la robustez con pocos datos y garantiza un funcionamiento inmediato desde el primer día de uso.
- TaskAgent - Motor híbrido de ML + reglas con post-procesamiento contextual
- Modelos de Base de Datos - Almacenamiento de modelos y datos de entrenamiento
- Endpoints ML - API para interactuar con el sistema IA
# Datos recolectados de tareas completadas
{
"titulo": "Fix bug producción - servicio caído",
"descripcion": "Servicio crítico no responde, resolver inmediatamente",
"urgencia": "high",
"impacto": "high",
"energia_requerida": "high",
"duracion_estimada": 60,
"objetivo": 3 # prioridad numérica: low=1, medium=2, high=3
}# Características extraídas para el modelo usando mapeos fijos:
features = {
'urgencia_encoded': 2, # Mapeo fijo: low=0, medium=1, high=2
'impacto_encoded': 2, # Mapeo fijo: low=0, medium=1, high=2
'energia_encoded': 2, # Mapeo fijo: low=0, medium=1, high=2
'duracion_estimada': 60, # Minutos estimados
'longitud_descripcion': 58, # Caracteres en descripción
'tiene_urgente': 1, # 1 si contiene "urgent", "crític"
'tiene_bug': 1 # 1 si contiene "bug", "fix"
}Nota técnica: Se usan mapeos fijos en lugar de
LabelEncoderpara evitar problemas de persistencia. Esto garantiza que el modelo sea 100% portable y no requiera guardar estructuras de estado adicionales.
El modelo aprende a predecir la prioridad deseada en lugar de una métrica derivada:
# Mapeo directo de prioridad a número
PRIORIDAD_NUM = {"low": 1, "medium": 2, "high": 3}
objetivo = PRIORIDAD_NUM.get(task.priority_level, 2)
# En caso de feedback negativo reciente, se usa actual_priority del feedback
if feedback and feedback.actual_priority:
objetivo = PRIORIDAD_NUM.get(feedback.actual_priority, objetivo)modelo = DecisionTreeClassifier(
max_depth=4, # Evita overfitting con pocos datos
random_state=42, # Semilla para reproducibilidad
class_weight="balanced" # Maneja desequilibrios en prioridades
)- Ideal para pocos datos: Funciona bien con tan solo 3-5 tareas completadas
- Interpretable: Las decisiones del árbol son fáciles de entender y depurar
- Robusto: No requiere escalado de características ni ajustes finos
- Eficiente: Entrenamiento y predicción en milisegundos
# Extraer características en tiempo real
X_pred = [
[2, 2, 2, 60, 58, 1, 1], # Hotfix - seguridad
[0, 1, 1, 180, 45, 0, 0], # Refactorizar notificaciones
[1, 2, 0, 45, 30, 0, 0] # Revisar PR de colega
]
# Hacer predicción (prioridad: 1, 2 o 3)
predicciones = modelo.predict(X_pred)
# Resultado: [3, 1, 2]
# Aplicar post-procesamiento contextual
scores_ajustados = []
for prioridad, task in zip(predicciones, tasks):
score_base = float(prioridad)
ajuste = 1.0
# Ajuste por deadline próximo
if task.deadline and dias_hasta_deadline <= 1:
ajuste *= 1.4
# Ajuste por hora del día y energía
if hora_actual >= 18 and task.energy_required == "high":
ajuste *= 0.7
scores_ajustados.append(score_base * ajuste)- Score 3.0+: Tareas críticas (bugs, seguridad, deadlines vencidos)
- Score 2.0-2.9: Tareas importantes con impacto alto
- Score 1.0-1.9: Tareas de mantenimiento o bajo impacto
Después de la predicción (ML o reglas), se aplica un ajuste dinámico basado en el contexto actual del usuario:
def _post_procesamiento(self, resultados):
hora_actual = datetime.now().hour
# Ajuste por hora del día
if hora_actual >= 18:
if task.energy_required == "high":
puntaje_ml *= 0.7 # Penalizar tareas exigentes al final del día
elif task.energy_required == "low":
puntaje_ml *= 1.3 # Favorecer tareas ligeras en la noche
# Ajuste por feedback negativo reciente (últimas 24h)
if task.id in tareas_con_feedback_negativo_24h:
puntaje_ml *= 1.3 # El sistema subestimó esta tarea, aumentar prioridad
# Ajuste por deadline
if task.deadline:
dias = (task.deadline - datetime.now()).days
if dias < 0:
puntaje_ml *= 2.5 # Deadline vencido
elif dias == 0:
puntaje_ml *= 2.0 # Deadline hoy-- Tabla ai_models
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
model_type VARCHAR(50), -- "priority_predictor_v3"
model_version VARCHAR(20), -- "3.1"
model_data BYTEA, -- Modelo serializado con joblib
is_active BOOLEAN, -- Modelo activo
trained_at TIMESTAMP# Guardar modelo
buffer = BytesIO()
joblib.dump(modelo, buffer)
modelo_bin = buffer.getvalue()
# Cargar modelo
modelo = joblib.load(BytesIO(modelo_bin))Ventaja clave: Al no depender de
LabelEncoder, el modelo guardado es completo y autocontenido, eliminando errores comunes de "categoría desconocida" al reiniciar el servidor.
El sistema siempre usa reglas como base, y solo activa el ML cuando hay suficientes datos:
def predecir_prioridad_tareas(self, tasks):
completed_count = contar_tareas_completadas()
# Solo usa ML si hay ≥3 tareas completadas
if self.modelo is not None and completed_count >= 3:
return self._predecir_con_ml(tasks)
else:
return self._prioridad_por_reglas(tasks)def _prioridad_por_reglas(self, tasks):
for task in tasks:
puntaje = 2.0 # base medium
# Ajuste por palabras clave
if any(kw in task.title.lower() for kw in ['bug', 'fix', 'hotfix', 'seguridad']):
puntaje = 3.0 # Siempre alta prioridad
# Ajuste por metadatos
if task.urgency == "high":
puntaje *= 1.4
if task.impact == "high":
puntaje *= 1.3
# Ajuste por deadline
if task.deadline and dias_hasta_deadline <= 1:
puntaje *= 1.7
task.puntaje_ml = puntajeEl sistema reentrena el modelo inmediatamente cuando recibe feedback negativo:
@router.post("/{task_id}/feedback")
def submit_ml_feedback(...):
# Guardar feedback
if not was_useful: # Feedback negativo
agent = TaskAgent(db, user_id)
agent.entrenar_modelo_prioridad() # Reentrena con datos actualizados- El feedback negativo aumenta temporalmente la prioridad de esa tarea (1.3x) durante 24h
- El reentrenamiento usa todos los datos históricos + el nuevo feedback
- Se crea una nueva versión del modelo y se activa automáticamente
# Resultados del demo avanzado
{
"hotfix_score": 3.0,
"revisar_pr_score_antes": 2.8,
"revisar_pr_score_despues": 3.64, # Aumentó tras feedback negativo
"refactor_score": 2.0
}- Diferenciación clara: Tareas críticas vs mantenimiento tienen scores distintos
- Respuesta al feedback: El sistema corrige sus errores inmediatamente
- Consistencia: Mismo tipo de tarea → Score similar
- Mínimo: 3 tareas completadas con prioridad definida
- Óptimo: 5+ tareas con variedad de tipos (críticas, normales, mantenimiento)
- Ideal: Tareas con deadlines y feedback de usuario
- Tareas con descripciones claras
- Variedad en prioridades asignadas
- Feedback ocacional para ajuste fino
- Nuevos usuarios: Usa reglas desde el primer minuto (ML se activa tras 3 tareas completadas)
- Tareas atípicas: El sistema de reglas garantiza un comportamiento razonable
- Cambios de patrones: El reentrenamiento automático adapta el modelo gradualmente
- Entrenamiento: ~500ms con 5-10 tareas
- Predicción: ~50ms por lote de tareas
- Almacenamiento: ~200KB-1MB por modelo de usuario
GET /api/v1/ml_tasks/prioritizedDescripción: Obtiene las tareas pendientes ordenadas por el score de prioridad calculado por el modelo ML (incluyendo ajustes de post-procesamiento contextual).
Ejemplo de respuesta:
[
{
"id": "uuid-tarea",
"title": "Enviar reporte trimestral",
"priority_level": "high",
"ml_priority_score": 4.2,
"estimated_duration": 120,
"urgency": "high",
"impact": "high"
}
]Uso:
curl -H "Authorization: Bearer {token}" \
"http://localhost:8000/api/v1/ml_tasks/prioritized"POST /api/v1/ml_tasks/{task_id}/trainDescripción: Entrena el modelo ML cuando se completa una tarea, usando los datos reales de ejecución.
Ejemplo:
curl -X POST -H "Authorization: Bearer {token}" \
"http://localhost:8000/api/v1/ml_tasks/123e4567-e89b-12d3-a456-426614174000/train"Respuesta:
{
"message": "Modelo actualizado exitosamente",
"trained": true
}GET /api/v1/ml_tasks/{task_id}/recommended-timeDescripción: Obtiene el horario óptimo recomendado para ejecutar una tarea específica basado en su nivel de energía requerido y tipo de tarea.
Ejemplo:
curl -H "Authorization: Bearer {token}" \
"http://localhost:8000/api/v1/ml_tasks/123e4567-e89b-12d3-a456-426614174000/recommended-time"Respuesta:
{
"task_id": "123e4567-e89b-12d3-a456-426614174000",
"recommended_time": "08:00",
"message": "Horario recomendado: 08:00"
}POST /api/v1/ml_tasks/{task_id}/feedbackParámetros en cuerpo (JSON):
feedback_type: Tipo de feedback (priority, schedule, completion)was_useful: Si la predicción fue útil (true/false)actual_priority: Prioridad real que tuvo la tarea (opcional)actual_completion_time: Tiempo real de completado en minutos (opcional)
Ejemplo:
curl -X POST \
"http://localhost:8000/api/v1/ml_tasks/123e4567-e89b-12d3-a456-426614174000/feedback" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"feedback_type": "completion",
"was_useful": true,
"actual_completion_time": 35
}'Respuesta:
{
"message": "Feedback registrado exitosamente"
}Propósito: Verificar el funcionamiento de todos los endpoints ML y diagnosticar problemas.
Uso:
chmod +x scripts/diagnosticar_ml.sh
./scripts/diagnosticar_ml.shFuncionalidades:
- Verifica autenticación
- Prueba todos los endpoints ML
- Muestra scores de priorización
- Detecta problemas de configuración
Propósito: Inicializar la base de datos con datos de prueba y usuario administrador.
Uso:
python scripts/simulation/admin_init_simulation.pyFuncionalidades:
- Crea tablas de base de datos
- Genera usuario administrador
- Crea categorías de ejemplo
- Genera tareas de entrenamiento inicial
Credenciales por defecto:
- Email:
admin@taskapp.com - Contraseña:
Admin123!
Propósito: Ejecutar un flujo completo de demostración del sistema ML con validación de aprendizaje.
Uso:
chmod +x simulate3.sh
./simulate3.sh- Inicialización: Base de datos y usuario admin
- Creación y completado: 5 tareas con patrones claros
- Entrenamiento: Se activa ML tras completar 5 tareas
- Validación: Se crean 3 tareas de prueba y se verifica que el modelo prioriza correctamente
- Feedback y mejora: Se rechaza una predicción y se verifica que el score aumenta tras el reentrenamiento
- DecisionTreeClassifier para clasificación de prioridades
- Mapeos fijos para variables categóricas
- Sistema de Reglas Inteligentes como base permanente
- Post-procesamiento Contextual para adaptación en tiempo real
- Palabras clave en título y descripción ("bug", "urgente", "seguridad")
- Metadatos de la tarea (urgencia, impacto, energía requerida)
- Deadline y tiempo estimado
- Feedback reciente del usuario (últimas 24h)
- Hora actual del día
pip install scikit-learn pandas numpy joblib- 3 tareas completadas para activar el modelo ML
- Sistema de reglas siempre disponible desde el primer día
# 1. Inicializar sistema
python scripts/simulation/admin_init_simulation.py
# 2. Ejecutar simulación completa
./simulate3.sh
# 3. Diagnosticar ML
./scripts/diagnosticar_ml.shEl sistema de inteligencia artificial se entrena de forma intencional y basada en datos reales, con un enfoque híbrido que combina ML y reglas.
-
Llamada explícita al endpoint
/train:
Puede ser invocada manualmente o automáticamente tras completar tareas. -
Feedback negativo del usuario (
was_useful=false):
Dispara inmediatamente un reentrenamiento para corregir errores.
- Tareas marcadas como "completed"
- Prioridad original y prioridad real (del feedback)
- Metadatos: urgencia, impacto, energía requerida
- Características derivadas: palabras clave, deadline, duración
- Verificación: Solo entrena si hay ≥3 tareas completadas
- Preparación: Convierte tareas a características numéricas usando mapeos fijos
- Aprendizaje:
DecisionTreeClassifierpredice prioridad (1, 2, o 3) - Guardado: El modelo se serializa y almacena en la base de datos
- Reglas: Siempre activas (desde la primera tarea)
- ML: Se activa automáticamente con 3+ tareas completadas
El sistema nunca falla. Usa el sistema de reglas inteligentes que considera:
- Palabras clave en títulos ("bug", "urgente", "seguridad")
- Niveles de urgencia e impacto
- Deadlines próximos
- Energía requerida vs hora del día
La elección se basa en requisitos prácticos para un sistema de productividad personal:
- Funcionamiento inmediato: Debe ser útil desde el primer día
- Robustez con pocos datos: Muchos usuarios tendrán pocas tareas completadas
- Cero dependencia de estado: No debe fallar al reiniciar el servidor
- Interpretabilidad: Las decisiones deben ser lógicas y predecibles
-
DecisionTreeClassifier:
- Funciona con pocos datos (3-10 ejemplos)
- Es interpretable y no requiere escalado
- Evita overfitting con
max_depth=3
-
Mapeos fijos (en lugar de LabelEncoder):
- Elimina errores de persistencia ("categoría desconocida")
- El modelo es 100% portable y autocontenido
- Nunca falla al cargar después de un reinicio
- Entrenamiento: < 1 segundo con 5 tareas
- Predicción: Instantánea (< 50ms)
- Robustez: Funciona perfectamente tras reinicios del servidor
- Utilidad: Prioridades inteligentes desde el primer día, mejorando continuamente con el uso
Solución: Completar más tareas para generar historial de entrenamiento (mínimo 2 tareas completadas).
Solución: Verificar que las rutas usen /ml_tasks/ (con guión bajo _) y no /ml-tasks/. Verificar que las dependencias de ML estén instaladas y reiniciar el servidor.
Solución: Ejecutar el script de diagnóstico para identificar el problema específico. Verificar permisos de base de datos y espacio de almacenamiento.
| Variable | Descripción | Valor por Defecto |
|---|---|---|
| DATABASE_URL | URL de conexión a PostgreSQL | postgresql://postgres:password@localhost:5432/smart_task |
| ALLOWED_ORIGINS | Orígenes permitidos para CORS | http://localhost:3000,http://127.0.0.1:3000 |
| DEBUG | Modo debug | true |
- FastAPI - Framework web
- SQLAlchemy - ORM para base de datos
- PostgreSQL - Base de datos
- Uvicorn - Servidor ASGI
- Pydantic - Validación de datos
Eliminar el archivo app/api/__init__.py si existe.
Ejecutar:
pip install psycopg2-binaryVerificar que:
- PostgreSQL esté ejecutándose
- Las credenciales en
.envsean correctas - La base de datos
smart_taskexista
# Eliminar archivos __pycache__
find . -name "__pycache__" -type d -exec rm -rf {} +- Implementar autenticación JWT
- Agregar sistema de IA para priorización
- Implementar tests unitarios
- Configurar CI/CD
- Dockerizar la aplicación
