"""Funciones de lógica de negocio""" import logging from datetime import datetime from connection import get_connection from models import RegistroRequest, RegistroResponse, ActionRequest # Configurar logging logger = logging.getLogger(__name__) def crear_registro(datos: RegistroRequest) -> dict: """ Crea un nuevo registro en la base de datos. Args: datos: Objeto RegistroRequest con los datos del usuario Returns: dict: Información del registro creado o error """ conn = get_connection() if not conn: logger.error("❌ No se pudo conectar a la base de datos") return { "success": False, "error": "No se pudo conectar a la base de datos" } try: logger.info(f"🔗 Conexión establecida a BD") # Preparar datos uid = datos.uid display_name = datos.display_name pais = datos.pais correo = datos.correo fecha_registro = datos.fecha_registro or datetime.now() usos = datos.usos or 0 prompt = datos.prompt prompt_type = datos.prompt_type prompt_eval = datos.prompt_eval estilo = datos.estilo estilo_agregado = datos.estilo_agregado calificacion = datos.calificacion proveedor = datos.proveedor seed = datos.seed logger.info(f"📊 Datos a insertar - UID: {uid}, Usuario: {display_name}, País: {pais}, Email: {correo}, Prompt: {prompt}, Tipo: {prompt_type}, Eval: {prompt_eval}, Estilo: {estilo}, Estilo Agregado: {estilo_agregado}, Calificación: {calificacion}, Proveedor: {proveedor}") # Insertar en la BD cursor = conn.cursor() sql = """ INSERT INTO `creacion` (uid, display_name, pais, correo, fecha_registro, usos, prompt, prompt_type, prompt_eval, estilo, estilo_agregado, calificacion, proveedor, seed) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """ valores = ( uid, display_name, pais, correo, fecha_registro, usos, prompt, prompt_type, prompt_eval, estilo, estilo_agregado, calificacion, proveedor, seed ) cursor.execute(sql, valores) conn.commit() logger.info(f"✅ Registro insertado en BD") # Obtener el ID del registro recién creado nuevo_id = cursor.lastrowid logger.info(f"🔑 ID generado: {nuevo_id}") # Recuperar el registro creado cursor.execute( """ SELECT id, uid, display_name, pais, correo, fecha_registro, usos, prompt, prompt_type, prompt_eval, estilo, estilo_agregado, calificacion, proveedor, seed, created_at FROM `creacion` WHERE id = %s """, (nuevo_id,) ) registro = cursor.fetchone() cursor.close() conn.close() if registro: logger.info(f"✅ Registro recuperado exitosamente - ID: {registro[0]}") return { "success": True, "data": { "id": registro[0], "uid": registro[1], "display_name": registro[2], "pais": registro[3], "correo": registro[4], "fecha_registro": registro[5], "usos": registro[6], "prompt": registro[7], "prompt_type": registro[8], "prompt_eval": registro[9], "estilo": registro[10], "estilo_agregado": registro[11], "calificacion": registro[12], "proveedor": registro[13], "seed": registro[14], "created_at": registro[15] } } else: logger.error("❌ No se pudo recuperar el registro creado") return { "success": False, "error": "No se pudo recuperar el registro creado" } except Exception as e: logger.error(f"❌ Error al crear registro: {str(e)}") return { "success": False, "error": f"Error al crear registro: {str(e)}" } def obtener_registros(limit: int = 10, offset: int = 0) -> dict: """ Obtiene registros de la base de datos con paginación. Args: limit: Cantidad máxima de registros offset: Desplazamiento para paginación Returns: dict: Lista de registros o error """ conn = get_connection() if not conn: logger.error("❌ No se pudo conectar a la base de datos") return { "success": False, "error": "No se pudo conectar a la base de datos" } try: logger.info(f"🔗 Obteniendo registros - Limit: {limit}, Offset: {offset}") cursor = conn.cursor() # Obtener total de registros cursor.execute("SELECT COUNT(*) FROM `creacion`") total = cursor.fetchone()[0] logger.info(f"📊 Total de registros en BD: {total}") # Obtener registros con paginación cursor.execute( """ SELECT id, uid, display_name, pais, correo, fecha_registro, usos, prompt, prompt_type, prompt_eval, estilo, estilo_agregado, calificacion, proveedor, seed, created_at FROM `creacion` ORDER BY created_at DESC LIMIT %s OFFSET %s """, (limit, offset) ) registros = cursor.fetchall() logger.info(f"✅ Se obtuvieron {len(registros)} registros de la BD") cursor.close() conn.close() # Convertir resultados datos = [] for reg in registros: datos.append({ "id": reg[0], "uid": reg[1], "display_name": reg[2], "pais": reg[3], "correo": reg[4], "fecha_registro": reg[5], "usos": reg[6], "prompt": reg[7], "prompt_type": reg[8], "prompt_eval": reg[9], "estilo": reg[10], "estilo_agregado": reg[11], "calificacion": reg[12], "proveedor": reg[13], "seed": reg[14], "created_at": reg[15] }) logger.info(f"📈 Retornando {len(datos)} registros") return { "success": True, "data": datos, "total": total, "limit": limit, "offset": offset } except Exception as e: logger.error(f"❌ Error al obtener registros: {str(e)}") return { "success": False, "error": f"Error al obtener registros: {str(e)}" } def actualizar_calificacion(id_registro: int, calificacion: int) -> dict: """ Actualiza la calificación de un registro existente. Args: id_registro: ID del registro a actualizar calificacion: Nueva calificación Returns: dict: Información del registro actualizado o error """ conn = get_connection() if not conn: logger.error("❌ No se pudo conectar a la base de datos") return { "success": False, "error": "No se pudo conectar a la base de datos" } try: logger.info(f"🔗 Actualizando calificación - ID: {id_registro}, Calificación: {calificacion}") cursor = conn.cursor() # Actualizar la calificación cursor.execute( "UPDATE `creacion` SET calificacion = %s WHERE id = %s", (calificacion, id_registro) ) conn.commit() if cursor.rowcount == 0: logger.error(f"❌ No se encontró registro con ID: {id_registro}") cursor.close() conn.close() return { "success": False, "error": f"No se encontró registro con ID: {id_registro}" } logger.info(f"✅ Calificación actualizada para ID: {id_registro}") # Recuperar el registro actualizado cursor.execute( """ SELECT id, uid, display_name, pais, correo, fecha_registro, usos, prompt, prompt_type, prompt_eval, estilo, estilo_agregado, calificacion, proveedor, seed, created_at FROM `creacion` WHERE id = %s """, (id_registro,) ) registro = cursor.fetchone() cursor.close() conn.close() if registro: logger.info(f"✅ Registro recuperado - ID: {registro[0]}") return { "success": True, "data": { "id": registro[0], "uid": registro[1], "display_name": registro[2], "pais": registro[3], "correo": registro[4], "fecha_registro": registro[5], "usos": registro[6], "prompt": registro[7], "prompt_type": registro[8], "prompt_eval": registro[9], "estilo": registro[10], "estilo_agregado": registro[11], "calificacion": registro[12], "proveedor": registro[13], "seed": registro[14], "created_at": registro[15] } } else: logger.error("❌ No se pudo recuperar el registro actualizado") return { "success": False, "error": "No se pudo recuperar el registro actualizado" } except Exception as e: logger.error(f"❌ Error al actualizar calificación: {str(e)}") return { "success": False, "error": f"Error al actualizar calificación: {str(e)}" } def crear_o_actualizar_action(datos: ActionRequest) -> dict: """ Crea o actualiza un registro en la tabla action_call. Args: datos: Objeto ActionRequest con los datos del usuario Returns: dict: Información del action creado/actualizado o error """ conn = get_connection() if not conn: logger.error("❌ No se pudo conectar a la base de datos") return { "success": False, "error": "No se pudo conectar a la base de datos" } try: logger.info(f"🔗 Conexión establecida a BD") cursor = conn.cursor() # Preparar los valores valores = ( datos.usuario, datos.uid, datos.displayName, datos.email, datos.action_call, datos.trigger_action, datos.country_header, datos.country_ip, datos.creditos, datos.esta_hora, datos.explicit_counter, datos.fecha_registro, datos.gaClient, datos.open_use, datos.ritmo, datos.streak, datos.ultima_generacion_hora, datos.ultimo_uso, datos.usos ) logger.info(f"📊 Datos a insertar/actualizar - Usuario: {datos.usuario}, Email: {datos.email}, Usos: {datos.usos}") # Usar INSERT ... ON DUPLICATE KEY UPDATE para crear o actualizar sql = """ INSERT INTO `action_call` (usuario, uid, displayName, email, action_call, trigger_action, country_header, country_ip, creditos, esta_hora, explicit_counter, fecha_registro, gaClient, open_use, ritmo, streak, ultima_generacion_hora, ultimo_uso, usos) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE uid = VALUES(uid), displayName = VALUES(displayName), email = VALUES(email), action_call = VALUES(action_call), trigger_action = VALUES(trigger_action), country_header = VALUES(country_header), country_ip = VALUES(country_ip), creditos = VALUES(creditos), esta_hora = VALUES(esta_hora), explicit_counter = VALUES(explicit_counter), fecha_registro = VALUES(fecha_registro), gaClient = VALUES(gaClient), open_use = VALUES(open_use), ritmo = VALUES(ritmo), streak = VALUES(streak), ultima_generacion_hora = VALUES(ultima_generacion_hora), ultimo_uso = VALUES(ultimo_uso), usos = VALUES(usos) """ cursor.execute(sql, valores) conn.commit() logger.info(f"✅ Action insertado/actualizado en BD") # Recuperar el action cursor.execute( "SELECT * FROM `action_call` WHERE usuario = %s", (datos.usuario,) ) action = cursor.fetchone() cursor.close() conn.close() if action: logger.info(f"✅ Action recuperado - Usuario: {action[1]}") return { "success": True, "data": { "id": action[0], "usuario": action[1], "uid": action[2], "displayName": action[3], "email": action[4], "action_call": action[5], "trigger_action": action[6], "country_header": action[7], "country_ip": action[8], "creditos": action[9], "esta_hora": action[10], "explicit_counter": action[11], "fecha_registro": action[12], "gaClient": action[13], "open_use": action[14], "ritmo": action[15], "streak": action[16], "ultima_generacion_hora": action[17], "ultimo_uso": action[18], "usos": action[19], "created_at": action[20], "updated_at": action[21] } } else: logger.error("❌ No se pudo recuperar el action") return { "success": False, "error": "No se pudo recuperar el action" } except Exception as e: logger.error(f"❌ Error al crear/actualizar action: {str(e)}") return { "success": False, "error": f"Error al crear/actualizar action: {str(e)}" } def obtener_action(usuario: str) -> dict: """ Obtiene un action específico por usuario. Args: usuario: Nombre de usuario Returns: dict: Información del action o error """ conn = get_connection() if not conn: logger.error("❌ No se pudo conectar a la base de datos") return { "success": False, "error": "No se pudo conectar a la base de datos" } try: logger.info(f"🔍 Buscando action - Usuario: {usuario}") cursor = conn.cursor() cursor.execute( "SELECT * FROM `action_call` WHERE usuario = %s", (usuario,) ) action = cursor.fetchone() cursor.close() conn.close() if action: logger.info(f"✅ Action encontrado - Usuario: {usuario}") return { "success": True, "data": { "id": action[0], "usuario": action[1], "uid": action[2], "displayName": action[3], "email": action[4], "action_call": action[5], "trigger_action": action[6], "country_header": action[7], "country_ip": action[8], "creditos": action[9], "esta_hora": action[10], "explicit_counter": action[11], "fecha_registro": action[12], "gaClient": action[13], "open_use": action[14], "ritmo": action[15], "streak": action[16], "ultima_generacion_hora": action[17], "ultimo_uso": action[18], "usos": action[19], "created_at": action[20], "updated_at": action[21] } } else: logger.error(f"❌ No se encontró action - Usuario: {usuario}") return { "success": False, "error": f"No se encontró action para el usuario: {usuario}" } except Exception as e: logger.error(f"❌ Error al obtener action: {str(e)}") return { "success": False, "error": f"Error al obtener action: {str(e)}" } def obtener_todas_acciones(limit: int = 10, offset: int = 0) -> dict: """ Obtiene todas las acciones con paginación. Args: limit: Cantidad máxima de registros offset: Desplazamiento para paginación Returns: dict: Lista de acciones o error """ conn = get_connection() if not conn: logger.error("❌ No se pudo conectar a la base de datos") return { "success": False, "error": "No se pudo conectar a la base de datos" } try: logger.info(f"📚 Obteniendo todas las acciones - Limit: {limit}, Offset: {offset}") cursor = conn.cursor() # Obtener total cursor.execute("SELECT COUNT(*) FROM `action_call`") total = cursor.fetchone()[0] logger.info(f"📊 Total de acciones: {total}") # Obtener con paginación cursor.execute( "SELECT * FROM `action_call` ORDER BY updated_at DESC LIMIT %s OFFSET %s", (limit, offset) ) acciones = cursor.fetchall() logger.info(f"✅ Se obtuvieron {len(acciones)} acciones") cursor.close() conn.close() datos = [] for action in acciones: datos.append({ "id": action[0], "usuario": action[1], "uid": action[2], "displayName": action[3], "email": action[4], "action_call": action[5], "trigger_action": action[6], "country_header": action[7], "country_ip": action[8], "creditos": action[9], "esta_hora": action[10], "explicit_counter": action[11], "fecha_registro": action[12], "gaClient": action[13], "open_use": action[14], "ritmo": action[15], "streak": action[16], "ultima_generacion_hora": action[17], "ultimo_uso": action[18], "usos": action[19], "created_at": action[20], "updated_at": action[21] }) return { "success": True, "data": datos, "total": total, "limit": limit, "offset": offset } except Exception as e: logger.error(f"❌ Error al obtener acciones: {str(e)}") return { "success": False, "error": f"Error al obtener acciones: {str(e)}" } def crear_evento_funel(datos) -> dict: """ Crea un evento en el funel de compra. Args: datos: Object FunelCompraRequest con usuario, mail, accion Returns: dict: Evento creado o error """ conn = get_connection() if not conn: logger.error("❌ No se pudo conectar a la base de datos") return { "success": False, "error": "No se pudo conectar a la base de datos" } try: logger.info(f"📊 Registrando evento funel - Usuario: {datos.usuario}, Mail: {datos.mail}, Acción: {datos.accion}") cursor = conn.cursor() sql = """ INSERT INTO `funel_compra` (usuario, mail, accion) VALUES (%s, %s, %s) """ valores = (datos.usuario, datos.mail, datos.accion) cursor.execute(sql, valores) conn.commit() logger.info(f"✅ Evento funel registrado en BD - Usuario: {datos.usuario}") # Recuperar el evento creado cursor.execute( "SELECT * FROM `funel_compra` WHERE usuario = %s AND mail = %s AND accion = %s ORDER BY created_at DESC LIMIT 1", (datos.usuario, datos.mail, datos.accion) ) evento = cursor.fetchone() cursor.close() conn.close() if evento: logger.info(f"✅ Evento recuperado - ID: {evento[0]}") return { "success": True, "data": { "id": evento[0], "usuario": evento[1], "mail": evento[2], "accion": evento[3], "created_at": evento[4] } } else: logger.error("❌ No se pudo recuperar el evento creado") return { "success": False, "error": "No se pudo recuperar el evento" } except Exception as e: logger.error(f"❌ Error al crear evento funel: {str(e)}") return { "success": False, "error": f"Error al crear evento: {str(e)}" } def obtener_eventos_funel(usuario: str) -> dict: """ Obtiene todos los eventos de funel para un usuario. Args: usuario: Nombre del usuario Returns: dict: Lista de eventos o error """ conn = get_connection() if not conn: logger.error("❌ No se pudo conectar a la base de datos") return { "success": False, "error": "No se pudo conectar a la base de datos" } try: logger.info(f"🔍 Buscando eventos funel - Usuario: {usuario}") cursor = conn.cursor() cursor.execute( "SELECT * FROM `funel_compra` WHERE usuario = %s ORDER BY created_at DESC", (usuario,) ) eventos = cursor.fetchall() cursor.close() conn.close() datos = [] for evento in eventos: datos.append({ "id": evento[0], "usuario": evento[1], "mail": evento[2], "accion": evento[3], "created_at": evento[4] }) logger.info(f"✅ Se obtuvieron {len(datos)} eventos para el usuario: {usuario}") return { "success": True, "data": datos, "total": len(datos) } except Exception as e: logger.error(f"❌ Error al obtener eventos funel: {str(e)}") return { "success": False, "error": f"Error al obtener eventos: {str(e)}" } def obtener_todos_eventos_funel(limit: int = 10, offset: int = 0) -> dict: """ Obtiene todos los eventos del funel con paginación. Args: limit: Cantidad máxima de registros offset: Desplazamiento para paginación Returns: dict: Lista de eventos paginada o error """ conn = get_connection() if not conn: logger.error("❌ No se pudo conectar a la base de datos") return { "success": False, "error": "No se pudo conectar a la base de datos" } try: logger.info(f"📚 Obteniendo todos los eventos funel - Limit: {limit}, Offset: {offset}") cursor = conn.cursor() # Obtener total cursor.execute("SELECT COUNT(*) FROM `funel_compra`") total = cursor.fetchone()[0] logger.info(f"📊 Total de eventos: {total}") # Obtener con paginación cursor.execute( "SELECT * FROM `funel_compra` ORDER BY created_at DESC LIMIT %s OFFSET %s", (limit, offset) ) eventos = cursor.fetchall() logger.info(f"✅ Se obtuvieron {len(eventos)} eventos") cursor.close() conn.close() datos = [] for evento in eventos: datos.append({ "id": evento[0], "usuario": evento[1], "mail": evento[2], "accion": evento[3], "created_at": evento[4] }) return { "success": True, "data": datos, "total": total, "limit": limit, "offset": offset } except Exception as e: logger.error(f"❌ Error al obtener eventos funel: {str(e)}") return { "success": False, "error": f"Error al obtener eventos: {str(e)}" }