diff --git a/src/app.py b/src/app.py index 2a3523c..eb45585 100644 --- a/src/app.py +++ b/src/app.py @@ -166,6 +166,7 @@ def recommend_gruas(): - dow: día de la semana (0-6, requerido) - hour: hora del día (0-23, requerido) - k: número de grúas (opcional, default=2) + - traffic: nivel de tráfico 1=bajo, 2=medio, 3=alto (opcional, default=1) - optimize: si es True, encuentra k óptimo (opcional, default=False) - min_gruas: mínimo de grúas para optimización (opcional, default=1) - max_gruas: máximo de grúas para optimización (opcional, default=10) @@ -178,6 +179,7 @@ def recommend_gruas(): hour = int(request.args["hour"]) k = request.args.get("k", default=2, type=int) + traffic = request.args.get("traffic", default=1, type=int) optimize = request.args.get("optimize", default="false").lower() == "true" min_gruas = request.args.get("min_gruas", default=1, type=int) max_gruas = request.args.get("max_gruas", default=10, type=int) @@ -190,6 +192,8 @@ def recommend_gruas(): return jsonify({"error": "hour debe estar entre 0 y 23"}), 400 if k < 1: return jsonify({"error": "k debe ser al menos 1"}), 400 + if not (1 <= traffic <= 3): + return jsonify({"error": "traffic debe estar entre 1 (bajo) y 3 (alto)"}), 400 # Obtener modelos demand_model = model_manager.get_model("demand") @@ -201,10 +205,10 @@ def recommend_gruas(): }), 500 if DEBUG_MODE: - print(f"DEBUG: Building prediction grid for week={week}, dow={dow}, hour={hour}") + print(f"DEBUG: Building prediction grid for week={week}, dow={dow}, hour={hour}, traffic={traffic}") # Construir grilla de predicciones - df = build_prediction_grid(week, dow, hour, demand_model, nulo_model) + df = build_prediction_grid(week, dow, hour, demand_model, nulo_model, traffic_level=traffic) if df.empty: return jsonify({ @@ -234,6 +238,10 @@ def recommend_gruas(): "semana": week, "dia_semana": dow, "hora": hour, + "trafico": { + "nivel": traffic, + "descripcion": {1: "bajo", 2: "medio", 3: "alto"}.get(traffic, "desconocido") + }, "optimizacion": { "k_optimo": result['optimal_k'], "porcentaje_cobertura": result['coverage_percentage'], @@ -263,7 +271,11 @@ def recommend_gruas(): "hora": hour, "parametros": { "k": k, - "optimizacion": optimize + "optimizacion": optimize, + "trafico": { + "nivel": traffic, + "descripcion": {1: "bajo", 2: "medio", 3: "alto"}.get(traffic, "desconocido") + } }, "h3_recomendados": result['selected'], "estadisticas": result.get('statistics', []), @@ -505,7 +517,7 @@ def index(): "ruta": "/recommend", "metodo": "GET", "descripcion": "Recomendar ubicaciones para grúas", - "parametros": "week, dow, hour (requeridos), k, optimize, min_gruas, max_gruas, target_coverage (opcionales)" + "parametros": "week, dow, hour (requeridos), k, traffic (1-3), optimize, min_gruas, max_gruas, target_coverage (opcionales)" }, { "ruta": "/coverage/radius", diff --git a/src/core/placement.py b/src/core/placement.py index 7d84850..a75362e 100644 --- a/src/core/placement.py +++ b/src/core/placement.py @@ -3,22 +3,58 @@ import pandas as pd from typing import List, Set, Dict, Tuple import numpy as np -def coverage_radius(expected_demand: float) -> int: +def get_max_radius_by_traffic(traffic_level: int) -> int: """ - Determina el radio de cobertura según la demanda esperada, como medimos anteriormente + Determina el radio máximo de cobertura según el nivel de tráfico. - Nivel demanda | Radio H3 + Nivel tráfico | Radio H3 máximo + ---------------|---------------- + Bajo (1) | 18 + Medio (2) | 12 + Alto (3) | 9 + + Args: + traffic_level: Nivel de tráfico (1=bajo, 2=medio, 3=alto) + + Returns: + Radio máximo en hexágonos H3 + """ + traffic_limits = { + 1: 18, # Tráfico bajo + 2: 12, # Tráfico medio + 3: 9 # Tráfico alto + } + return traffic_limits.get(traffic_level, 18) # Default a tráfico bajo + +def coverage_radius(expected_demand: float, traffic_level: int = 1) -> int: + """ + Determina el radio de cobertura según la demanda esperada y el nivel de tráfico. + El radio final es el mínimo entre el radio calculado por demanda y el límite de tráfico. + + Nivel demanda | Radio H3 base ---------------|---------- baja (<2) | 18 media (2-5) | 12 alta (≥5) | 6 + + Args: + expected_demand: Demanda esperada + traffic_level: Nivel de tráfico (1=bajo, 2=medio, 3=alto) + + Returns: + Radio de cobertura ajustado por tráfico """ + # Radio base según demanda if expected_demand < 2: - return 18 + base_radius = 18 elif expected_demand < 5: - return 12 + base_radius = 12 else: - return 6 + base_radius = 6 + + # Aplicar restricción de tráfico + max_radius = get_max_radius_by_traffic(traffic_level) + return min(base_radius, max_radius) def get_coverage_weight(expected_demand: float) -> float: """ @@ -82,12 +118,14 @@ def calculate_coverage_score(cell: str, radius: int, df: pd.DataFrame) -> float: return total_risk * (1 + 0.1 * demand_weight) def build_prediction_grid(week: int, dow: int, hour: int, - demand_model, nulo_model, h3_resolution: int = 8) -> pd.DataFrame: + demand_model, nulo_model, h3_resolution: int = 8, + traffic_level: int = 1) -> pd.DataFrame: """ Construye una cuadricula de predicciones para todas las celdas H3. Args: h3_resolution: Resolución H3 (default=8 para áreas urbanas) + traffic_level: Nivel de tráfico (1=bajo, 2=medio, 3=alto) """ # Obtener todas las celdas H3 únicas de la base de datos from db import get_all_h3_cells @@ -117,8 +155,8 @@ def build_prediction_grid(week: int, dow: int, hour: int, # Calcular riesgo risk = calculate_risk(expected_demand, nulo_prob) - # Determinar radio de cobertura y peso - radius = coverage_radius(expected_demand) + # Determinar radio de cobertura y peso (ajustado por tráfico) + radius = coverage_radius(expected_demand, traffic_level) coverage_weight = get_coverage_weight(expected_demand) predictions.append({