Skip to content
This repository has been archived by the owner on Oct 18, 2024. It is now read-only.

Feature/rodrigo modelo #62

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
77 changes: 77 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
asgiref==3.8.1
cachetools==5.5.0
certifi==2024.8.30
cffi==1.17.1
charset-normalizer==3.3.2
colorama==0.4.6
cryptography==43.0.1
Django==5.1.1
django-allauth==64.2.1
django-oauth-toolkit==3.0.1
djangorestframework==3.15.2
djangorestframework-simplejwt==5.3.1
drf-yasg==1.21.7
filelock==3.16.0
fsspec==2024.9.0
google-api-core==2.19.2
google-api-python-client==2.145.0
google-auth==2.34.0
google-auth-httplib2==0.2.0
google-auth-oauthlib==1.2.1
googleapis-common-protos==1.65.0
grpcio==1.66.1
httplib2==0.22.0
huggingface-hub==0.24.7
idna==3.8
inflection==0.5.1
Jinja2==3.1.4
jwcrypto==1.5.6
MarkupSafe==2.1.5
mpmath==1.3.0
networkx==3.3
numpy==2.1.1
nvidia-cublas-cu12==12.1.3.1
nvidia-cuda-cupti-cu12==12.1.105
nvidia-cuda-nvrtc-cu12==12.1.105
nvidia-cuda-runtime-cu12==12.1.105
nvidia-cudnn-cu12==9.1.0.70
nvidia-cufft-cu12==11.0.2.54
nvidia-curand-cu12==10.3.2.106
nvidia-cusolver-cu12==11.4.5.107
nvidia-cusparse-cu12==12.1.0.106
nvidia-nccl-cu12==2.20.5
nvidia-nvjitlink-cu12==12.6.68
nvidia-nvtx-cu12==12.1.105
oauthlib==3.2.2
packaging==24.1
pandas==2.2.3
proto-plus==1.24.0
protobuf==5.28.1
psycopg2==2.9.9
psycopg2-binary==2.9.9
pyasn1==0.6.1
pyasn1_modules==0.4.1
pycparser==2.22
PyJWT==2.9.0
pyparsing==3.1.4
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
pytz==2024.2
PyYAML==6.0.2
regex==2024.9.11
requests==2.32.3
requests-oauthlib==2.0.0
rsa==4.9
safetensors==0.4.5
six==1.16.0
sqlparse==0.5.1
sympy==1.13.2
tokenizers==0.19.1
torch==2.4.1
tqdm==4.66.5
transformers==4.44.2
triton==3.0.0
typing_extensions==4.12.2
tzdata==2024.1
uritemplate==4.1.1
urllib3==2.2.3
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 5.1.1 on 2024-10-10 20:35

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api', '0007_alter_campana_table'),
]

operations = [
migrations.AddField(
model_name='campana',
name='presupuesto',
field=models.FloatField(blank=True, null=True),
),
migrations.AddField(
model_name='campana',
name='tamaño_audiencia',
field=models.IntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='campana',
name='tipo_campana',
field=models.CharField(choices=[('email', 'Email Marketing'), ('google_ads', 'Google Ads'), ('social_media', 'Social Media'), ('banner', 'Banner Advertising')], default='email', max_length=50),
),
]
18 changes: 18 additions & 0 deletions site_app/api/migrations/0009_campana_fecha_finalizacion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1.1 on 2024-10-10 21:20

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api', '0008_campana_presupuesto_campana_tamaño_audiencia_and_more'),
]

operations = [
migrations.AddField(
model_name='campana',
name='fecha_finalizacion',
field=models.DateField(blank=True, null=True),
),
]
17 changes: 17 additions & 0 deletions site_app/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,27 @@ class Meta:

# Campana gestionadas por User
class Campana(models.Model):
# Definir las opciones como un enumerado
EMAIL = 'email'
GOOGLE_ADS = 'google_ads'
SOCIAL_MEDIA = 'social_media'
BANNER = 'banner'

TIPO_CAMPANA_CHOICES = [
(EMAIL, 'Email Marketing'),
(GOOGLE_ADS, 'Google Ads'),
(SOCIAL_MEDIA, 'Social Media'),
(BANNER, 'Banner Advertising'),
]

id = models.AutoField(primary_key=True)
nombre = models.CharField(max_length=255)
descripcion = models.TextField()
fecha_creacion = models.DateTimeField(auto_now_add=True)
fecha_inicio = models.DateField(null=True, blank=True)
fecha_finalizacion = models.DateField(null=True ,blank=True)
usuario = models.ForeignKey('api.Usuario', on_delete=models.CASCADE)
tipo_campana = models.CharField(max_length=50, choices=TIPO_CAMPANA_CHOICES, default=EMAIL)
rendimiento = models.OneToOneField(
'api.EstadisticaCampana',
on_delete=models.CASCADE,
Expand All @@ -112,6 +127,8 @@ class Campana(models.Model):
conversiones_totales = models.IntegerField(default=0)
google_calendar_event_id = models.CharField(max_length=255, null=True, blank=True)
google_keep_note_id = models.CharField(max_length=255, null=True, blank=True)
presupuesto = models.FloatField(null=True, blank=True)
tamaño_audiencia = models.IntegerField(null=True, blank=True) # target_audience_size

class Meta:
db_table = 'campanas'
Expand Down
17 changes: 17 additions & 0 deletions site_app/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,20 @@ def create(self, validated_data):
usuario.save() # Guarda la nueva instancia de usuario en la base de datos
return usuario # Devuelve el usuario recién creado

class PredecirRendimientoSerializer(serializers.Serializer):
tipo_campana = serializers.ChoiceField(choices=[
('email', 'Email Marketing'),
('google_ads', 'Google Ads'),
('social_media', 'Social Media'),
('banner', 'Banner Advertising'),
])
fecha_inicio = serializers.DateField()
fecha_finalizacion = serializers.DateField()
presupuesto = serializers.FloatField()
tamaño_audiencia = serializers.IntegerField()

# Validación para asegurarse de que la fecha_finalización sea posterior a la fecha_inicio
def validate(self, data):
if data['fecha_finalizacion'] <= data['fecha_inicio']:
raise serializers.ValidationError("La fecha de finalización debe ser posterior a la fecha de inicio.")
return data
37 changes: 34 additions & 3 deletions site_app/api/services/CampanaService.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,47 @@
from datetime import timedelta
from django.db import IntegrityError
from django.core.exceptions import ObjectDoesNotExist
import pickle
import pandas as pd

class CampanaService:
def __init__(self):
self.generador_texto = pipeline("text-generation", model="facebook/bart-large-cnn")
self.campana_repository = CampanaRepository()

def calcular_rendimiento(self, estadistica ):
# Cargar el modelo de regresión
model_filename = 'modelo_regresion.pkl'
with open(model_filename, 'rb') as file:
self.loaded_model = pickle.load(file)

def calcular_rendimiento(self, campana):
# Lógica para calcular el rendimiento utilizando las estadísticas
rendimiento = (estadistica.tasa_apertura + estadistica.tasa_conversion) / 2
return rendimiento
# rendimiento = (estadistica.tasa_apertura + estadistica.tasa_conversion) / 2
# return rendimiento

# Extraer datos de la campaña
campaign_type = campana.tipo_campana
duration_days = (campana.fecha_finalizacion - campana.fecha_inicio).days
budget = campana.presupuesto
target_audience_size = campana.tamaño_audiencia

# Crear un DataFrame con los datos de entrada para el modelo
input_data = pd.DataFrame({
'duration_days': [duration_days],
'budget': [budget],
'target_audience_size': [target_audience_size],
'campaign_type_email': [True if campaign_type == Campana.EMAIL else False],
'campaign_type_google_ads': [True if campaign_type == Campana.GOOGLE_ADS else False],
'campaign_type_social_media': [True if campaign_type == Campana.SOCIAL_MEDIA else False],
'campaign_type_banner': [True if campaign_type == Campana.BANNER else False]
})

# Realizar la predicción utilizando el modelo de regresión cargado
predicted_rendimiento = self.loaded_model.predict(input_data)[0]

# Retornar el rendimiento predicho
return predicted_rendimiento


def crear_campana_con_contenido(self, data):
serializer = CampanaSerializer(data=data)
Expand Down
Binary file added site_app/api/services/modelo_regresion.pkl
Binary file not shown.
11 changes: 10 additions & 1 deletion site_app/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from api.controllers.CampanaController import CampanaViewSet
from api.controllers.UsuarioController import UsuarioViewSet
from api import views
from .views.view import TareaViewSet, CampanaViewSet,CampanaCrearViewSet, ClienteViewSet, AgregarClienteViewSet, EstadisticasCampanaViewSet, ImportarDatosView,CalendarView,fetch_events, TareaGoogleCalendarView
from .views.view import TareaViewSet, CampanaViewSet,CampanaCrearViewSet, ClienteViewSet, EstadisticasCampanaViewSet, ImportarDatosView,CalendarView,fetch_events, TareaGoogleCalendarView, CustomTokenObtainPairView, CustomTokenRefreshView, TokenRefreshView, PredecirRendimientoView
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

Expand Down Expand Up @@ -36,6 +36,8 @@
# Permite importar datos de clientes desde un archivo CSV o similar.
path('datos/importar/', ImportarDatosView.as_view(), name='importar_datos'),



# Integración con Google Calendar
path('fetch-events/', fetch_events, name='fetch_events'),
path('', include('api.calendar_integration.urls')),
Expand All @@ -51,4 +53,11 @@

# Esta ruta para crear campañas es correcta
path('campanas/crear/', CampanaCrearViewSet.as_view(), name='campana_crear'),
path('campanas/predecir_rendimiento/', PredecirRendimientoView.as_view(), name='predecir_rendimiento'),

path('api/token/', CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', CustomTokenRefreshView.as_view(), name='token_refresh'),

# Swagger UI
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]
74 changes: 73 additions & 1 deletion site_app/api/views/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from django.db import IntegrityError
from rest_framework import generics
from django.shortcuts import get_object_or_404
import csv
from ..services import EstadisticasService,CampanaService,ClienteService,google_calendarService
from ..services.CampanaService import CampanaService
from ..models import Tarea, Campana, Cliente, EstadisticaCampana,Usuario, Event
from ..serializers import TareaSerializer, CampanaSerializer, ClienteSerializer, EstadisticaCampanaSerializer, EventSerializer
from ..serializers import TareaSerializer, CampanaSerializer, ClienteSerializer, EstadisticaCampanaSerializer, PredecirRendimientoSerializer
from ..repositories import TareasRepository,CampanaRepository,ClienteRepository,EstadisticasRepository
from transformers import pipeline
import csv
Expand Down Expand Up @@ -238,3 +239,74 @@ def post(self, request):
def fetch_events_view(request):
calendar_service = google_calendarService ()
events = calendar_service.fetch_events()



class CustomTokenObtainPairView(TokenObtainPairView):
@swagger_auto_schema(
operation_description="Obtener un token JWT",
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'username': openapi.Schema(type=openapi.TYPE_STRING, description='Nombre de usuario o correo electrónico'),
'password': openapi.Schema(type=openapi.TYPE_STRING, description='Contraseña'),
},
),
responses={200: openapi.Response('Success', openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'refresh': openapi.Schema(type=openapi.TYPE_STRING, description='Token de refresco'),
'access': openapi.Schema(type=openapi.TYPE_STRING, description='Token de acceso'),
},
))},
)
def post(self, request, *args, **kwargs):
return super().post(request, *args, **kwargs)


class CustomTokenRefreshView(TokenRefreshView):
pass

class PredecirRendimientoView(APIView):

@swagger_auto_schema(
request_body=PredecirRendimientoSerializer,
responses={
200: openapi.Response('Rendimiento predicho', PredecirRendimientoSerializer),
400: 'Error en los datos de entrada'
}
)

def post(self, request):
# Validar los datos con el serializer
serializer = PredecirRendimientoSerializer(data=request.data)

if serializer.is_valid():
# Los datos ya están validados y se pueden extraer del serializer
validated_data = serializer.validated_data

# Instanciar el servicio de la campaña
campana_service = CampanaService()

# Simular una "campaña" temporal con los datos validados
class SimulatedCampana:
def __init__(self, data):
self.tipo_campana = data['tipo_campana']
self.fecha_inicio = data['fecha_inicio']
self.fecha_finalizacion = data['fecha_finalizacion']
self.presupuesto = data['presupuesto']
self.tamaño_audiencia = data['tamaño_audiencia']

# Crear la campaña simulada
campana = SimulatedCampana(validated_data)

# Llamar al método para calcular el rendimiento
rendimiento = campana_service.calcular_rendimiento(campana)

# Retornar la respuesta con el rendimiento predicho
return Response({
'rendimiento_predicho': rendimiento
}, status=status.HTTP_200_OK)

# Si el serializer no es válido, retornar los errores
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Loading