diff --git a/bin/rate_update.py b/bin/rate_update.py index 07903f0..3b93e45 100755 --- a/bin/rate_update.py +++ b/bin/rate_update.py @@ -209,57 +209,129 @@ def query_perplexity(prompt, model="o1"): content = result.get('choices', [{}])[0].get('message', {}).get('content', '') logger.info(f"Contenido de la respuesta: {content}") + # Primero, detectar si la respuesta menciona un período de tiempo diferente a hora + period_indicators = { + 'hora': 1, # Factor de conversión a hora (1 hora = 1 hora) + 'día': 1/8, # Asumiendo jornada de 8 horas + 'semana': 1/40, # Asumiendo 40 horas semanales + 'mes': 1/160, # Asumiendo ~160 horas mensuales (40 h/sem * 4 sem) + 'año': 1/2000, # Asumiendo ~2000 horas anuales + 'anual': 1/2000, + 'mensual': 1/160, + 'semanal': 1/40, + 'diario': 1/8, + 'por hora': 1, + 'por día': 1/8, + 'por semana': 1/40, + 'por mes': 1/160, + 'por año': 1/2000, + 'por jornada': 1/8 + } + + # Detectar el período mencionado en el texto + time_period_factor = 1 # Por defecto asumimos que el valor ya está por hora + for period, factor in period_indicators.items(): + if period in content.lower(): + time_period_factor = factor + logger.info(f"Detectado período de tiempo: {period} (factor: {factor})") + break + # Estrategia 1: Buscar patrones específicos de dinero (con y sin símbolo de dólar) # Buscar un patrón como $30.00, 30.00, $30, o 30 USD money_patterns = [ - r'\$(\d+\.\d{2})', # $30.00 - r'(\d+\.\d{2})\s*USD', # 30.00 USD - r'(\d+\.\d{2})', # 30.00 - r'\$(\d+)', # $30 - r'(\d+)\s*USD', # 30 USD - r'(\d+(?:\.\d+)?)' # Cualquier número con o sin decimales + r'\$\s*(\d{1,3}(?:,\d{3})*(?:\.\d{2}))', # $30,000.00 o $30.00 + r'(\d{1,3}(?:,\d{3})*(?:\.\d{2}))\s*USD', # 30,000.00 USD o 30.00 USD + r'\$\s*(\d{1,3}(?:,\d{3})*)', # $30,000 o $30 + r'(\d{1,3}(?:,\d{3})*)\s*USD', # 30,000 USD o 30 USD + r'\$\s*(\d+\.\d{2})', # $30.00 + r'(\d+\.\d{2})\s*USD', # 30.00 USD + r'\$\s*(\d+)', # $30 + r'(\d+)\s*USD', # 30 USD + r'(\d+(?:\.\d+)?)' # Cualquier número con o sin decimales ] for pattern in money_patterns: match = re.search(pattern, content) if match: try: - value = float(match.group(1)) - logger.info(f"Valor extraído con patrón {pattern}: {value}") - return round(value, 2) # Asegurar 2 decimales + # Limpiar comas para poder convertir a float + value_str = match.group(1).replace(',', '') + value = float(value_str) + + # Convertir a tarifa por hora según el período detectado + hourly_rate = value * time_period_factor + + logger.info(f"Valor extraído: {value} (periodo factor: {time_period_factor})") + logger.info(f"Convertido a tarifa por hora: {hourly_rate:.2f}") + + return round(hourly_rate, 2) # Asegurar 2 decimales except (ValueError, IndexError): continue # Estrategia 2: Extraer todos los números y elegir el más probable - all_numbers = re.findall(r'\d+(?:\.\d+)?', content) + all_numbers = re.findall(r'\d{1,3}(?:,\d{3})*(?:\.\d+)?|\d+(?:\.\d+)?', content) if all_numbers: try: + # Limpiar comas y convertir a float + cleaned_numbers = [float(n.replace(',', '')) for n in all_numbers] + # Si hay varios números, elegir el más probable - # (En este caso, podríamos tomar el promedio o el primero) - if len(all_numbers) > 1: - logger.info(f"Múltiples números encontrados: {all_numbers}") - # Eliminamos valores extremadamente altos o bajos - filtered_numbers = [float(n) for n in all_numbers if 5 <= float(n) <= 500] + if len(cleaned_numbers) > 1: + logger.info(f"Múltiples números encontrados: {cleaned_numbers}") + # Eliminamos valores extremadamente altos o bajos según el período de tiempo + + # Definir rangos válidos según el factor de tiempo + min_valid = 5 + max_valid = 500 + + # Ajustar rangos según el período detectado + if time_period_factor == 1/8: # diario + min_valid = 40 + max_valid = 4000 + elif time_period_factor == 1/40: # semanal + min_valid = 200 + max_valid = 20000 + elif time_period_factor == 1/160: # mensual + min_valid = 800 + max_valid = 80000 + elif time_period_factor == 1/2000: # anual + min_valid = 10000 + max_valid = 1000000 + + filtered_numbers = [n for n in cleaned_numbers if min_valid <= n <= max_valid] + if filtered_numbers: value = sum(filtered_numbers) / len(filtered_numbers) else: - value = float(all_numbers[0]) + # Si no hay valores en el rango, tomar el primer número + value = cleaned_numbers[0] else: - value = float(all_numbers[0]) + value = cleaned_numbers[0] + + # Aplicar factor de conversión de tiempo + hourly_rate = value * time_period_factor - logger.info(f"Valor final extraído: {value}") - return round(value, 2) + logger.info(f"Valor extraído: {value} (período factor: {time_period_factor})") + logger.info(f"Convertido a tarifa por hora: {hourly_rate:.2f}") + + return round(hourly_rate, 2) except ValueError: pass # Estrategia 3: Último recurso, intentar limpiar el texto y extraer un número try: - # Eliminar cualquier símbolo de moneda y espacios + # Eliminar cualquier símbolo que no sea dígito o punto cleaned_content = re.sub(r'[^\d.]', '', content) if cleaned_content: - value = round(float(cleaned_content), 2) - logger.info(f"Valor limpiado y extraído: {value}") - return value + value = float(cleaned_content) + + # Aplicar factor de conversión de tiempo + hourly_rate = value * time_period_factor + + logger.info(f"Valor limpiado y extraído: {value} (período factor: {time_period_factor})") + logger.info(f"Convertido a tarifa por hora: {hourly_rate:.2f}") + + return round(hourly_rate, 2) except ValueError: pass @@ -402,7 +474,13 @@ def generate_prompt(programmer_type, region_code): # Usamos el año actual para la consulta principal current_year = time.strftime("%Y") - prompt = f"¿Cuál es la tarifa por hora promedio en dólares estadounidenses (USD) para un {programmer_description} en {region_name} en {current_year}? Si no tienes datos del {current_year}, usa la información más reciente y haz una estimación aproximada. Responde solo con el valor numérico con dos decimales." + prompt = f"""¿Cuál es la tarifa POR HORA promedio en dólares estadounidenses (USD) para un {programmer_description} en {region_name} en {current_year}? + +Si no tienes datos del {current_year}, usa la información más reciente y haz una estimación aproximada. + +IMPORTANTE: Si encuentras información en otros períodos de tiempo (mensual, anual, etc.), conviértela a tarifa POR HORA. + +Responde solo con el valor numérico con dos decimales.""" return prompt