From 604786ad5f5ed7dcdb69c6523005a89725cf49c0 Mon Sep 17 00:00:00 2001 From: "Mauro Rosero P." Date: Wed, 12 Mar 2025 12:57:08 -0500 Subject: [PATCH] =?UTF-8?q?[IMPROVED]=20Calcular=20tarifa=20de=20fullstack?= =?UTF-8?q?=20como=201.5=20veces=20el=20valor=20m=C3=A1ximo=20encontrado?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- bin/rate_update.py | 174 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/bin/rate_update.py b/bin/rate_update.py index 0bc0f3f..73cfdbf 100755 --- a/bin/rate_update.py +++ b/bin/rate_update.py @@ -448,6 +448,23 @@ def update_single_rate(programmer_type): # Crear la carpeta rates si no existe os.makedirs(RATES_DIR, exist_ok=True) + # Diccionario para almacenar las tarifas calculadas y existentes + rates_dict = {} + + # Si es fullstack, necesitamos primero obtener el valor más alto de todos los tipos + if programmer_type == 'fullstack': + # Leer las tarifas existentes + for prog_type in get_programmer_types(): + if prog_type != 'fullstack': + rate_file = RATES_DIR / f"{prog_type}.rate" + if rate_file.exists(): + try: + with open(rate_file, 'r', encoding='utf-8') as f: + rates_dict[prog_type] = float(f.read().strip()) + logger.info(f"Tarifa leída para {prog_type}: {rates_dict[prog_type]:.2f}") + except (FileNotFoundError, ValueError) as e: + logger.warning(f"Error al leer tarifa de {prog_type}: {e}") + # Si es bash, necesitamos primero obtener o actualizar la tarifa de devops devops_rate = None if programmer_type == 'bash': @@ -460,6 +477,7 @@ def update_single_rate(programmer_type): try: with open(devops_rate_file, 'r', encoding='utf-8') as f: devops_rate = float(f.read().strip()) + rates_dict['devops'] = devops_rate logger.info(f"Tarifa leída para devops: {devops_rate:.2f}") except (FileNotFoundError, ValueError) as e: logger.error(f"Error al leer tarifa de devops: {e}") @@ -502,6 +520,9 @@ def update_single_rate(programmer_type): with open(devops_rate_file, 'w', encoding='utf-8') as f: f.write(f"{devops_rate:.2f}") + # Añadir al diccionario + rates_dict['devops'] = devops_rate + # Mostrar el resultado en la consola result_message = f"Tarifa para devops: {devops_rate:.2f} USD/hora" logger.info(f"Actualizado archivo {devops_rate_file} con valor: {devops_rate:.2f}") @@ -518,6 +539,47 @@ def update_single_rate(programmer_type): logger.info(f"Calculando tarifa para bash como 0.4 * {devops_rate:.2f}") rate = 0.4 * devops_rate logger.info(f"Tarifa calculada para bash: {rate:.2f}") + # Caso especial para fullstack + elif programmer_type == 'fullstack': + # Primero calculamos el valor más alto entre todos los tipos + max_rate_value = 0.0 + for prog_type, rate_value in rates_dict.items(): + if prog_type != 'fullstack' and rate_value > max_rate_value: + max_rate_value = rate_value + + logger.info(f"Valor más alto encontrado: {max_rate_value:.2f}") + + # Obtener tarifa para fullstack vía API + api_rate = None + if api_available: + prompt = generate_prompt_base(programmer_type) + logger.info(f"Consultando tarifa para {programmer_type}") + + try: + # Consultar a Perplexity + api_rate = query_perplexity(prompt, model) + + if api_rate is not None: + logger.info(f"Tarifa obtenida correctamente: {api_rate:.2f}") + else: + logger.error(f"No se pudo obtener la tarifa para {programmer_type}") + except Exception as e: + logger.error(f"Error al consultar tarifa para {programmer_type}: {e}") + + # Si la API falló, usar el valor predeterminado + if api_rate is None: + logger.warning(f"Usando valor predeterminado para {programmer_type}") + api_rate = get_default_rate(programmer_type) + logger.info(f"Valor predeterminado: {api_rate:.2f}") + + # Calcular el valor de fullstack + # Si el valor de la API es menor o igual al valor más alto, usar 1.5 veces el valor más alto + if api_rate <= max_rate_value: + rate = 1.5 * max_rate_value + logger.info(f"API rate ({api_rate:.2f}) <= max rate ({max_rate_value:.2f}), ajustando fullstack a 1.5 * {max_rate_value:.2f} = {rate:.2f}") + else: + rate = api_rate + logger.info(f"API rate ({api_rate:.2f}) > max rate ({max_rate_value:.2f}), manteniendo valor API") else: # Para otros tipos, procedemos como antes prompt = generate_prompt_base(programmer_type) @@ -593,6 +655,23 @@ def update_rate_files(force_update=False): programmer_types = get_programmer_types() logger.info(f"Procesando {len(programmer_types)} tipos de programadores.") + # Diccionario para almacenar las tarifas ya calculadas + rates_dict = {} + + # Leer las tarifas existentes primero + if 'fullstack' in programmer_types: + # Primero leer los valores existentes de tipos que no vamos a actualizar + for prog_type in get_programmer_types(): + if prog_type not in programmer_types: + rate_file = RATES_DIR / f"{prog_type}.rate" + if rate_file.exists(): + try: + with open(rate_file, 'r', encoding='utf-8') as f: + rates_dict[prog_type] = float(f.read().strip()) + logger.info(f"Tarifa leída para {prog_type}: {rates_dict[prog_type]:.2f}") + except (FileNotFoundError, ValueError) as e: + logger.warning(f"Error al leer tarifa de {prog_type}: {e}") + # Procesamos primero devops siempre que force_update sea True o bash esté pendiente devops_rate = None need_devops_for_bash = ('bash' in programmer_types and (not (RATES_DIR / "bash.rate").exists() or force_update)) @@ -638,6 +717,9 @@ def update_rate_files(force_update=False): with open(devops_rate_file, 'w', encoding='utf-8') as f: f.write(f"{devops_rate:.2f}") + # Guardar en el diccionario de tarifas + rates_dict['devops'] = devops_rate + # Mostrar el resultado en la consola result_message = f"Tarifa para devops: {devops_rate:.2f} USD/hora" logger.info(f"{'Actualizado' if force_update else 'Creado'} archivo {devops_rate_file} con valor: {devops_rate:.2f}") @@ -657,18 +739,35 @@ def update_rate_files(force_update=False): try: with open(devops_rate_file, 'r', encoding='utf-8') as f: devops_rate = float(f.read().strip()) + rates_dict['devops'] = devops_rate logger.info(f"Tarifa leída para devops: {devops_rate:.2f}") except (FileNotFoundError, ValueError) as e: logger.error(f"Error al leer tarifa de devops: {e}") devops_rate = get_default_rate('devops') + rates_dict['devops'] = devops_rate - # Procesar cada tipo de programador + # Procesar los demás tipos de programador antes de fullstack + fullstack_type = None + if 'fullstack' in programmer_types: + # Guardar para procesarlo después + fullstack_type = 'fullstack' + # Eliminarlo temporalmente de la lista + programmer_types.remove('fullstack') + + # Procesar cada tipo de programador (excepto fullstack) for programmer_type in programmer_types: # Comprobar si ya existe el archivo para este tipo de programador rate_file = RATES_DIR / f"{programmer_type}.rate" # Si el archivo ya existe y no estamos forzando la actualización, saltamos este tipo if rate_file.exists() and not force_update: + # Leer el valor para almacenarlo en el diccionario + try: + with open(rate_file, 'r', encoding='utf-8') as f: + rates_dict[programmer_type] = float(f.read().strip()) + except (FileNotFoundError, ValueError) as e: + logger.warning(f"Error al leer archivo {rate_file}: {e}") + logger.info(f"El archivo {rate_file} ya existe. Saltando.") continue @@ -713,6 +812,9 @@ def update_rate_files(force_update=False): logger.warning(f"Ajustando tarifa {rate:.2f} al máximo permitido de {max_rate}") rate = max_rate + # Guardar la tarifa en el diccionario + rates_dict[programmer_type] = rate + # Guardar el resultado en el archivo - solo el valor numérico con dos decimales, sin salto de línea with open(rate_file, 'w', encoding='utf-8') as f: f.write(f"{rate:.2f}") @@ -724,6 +826,76 @@ def update_rate_files(force_update=False): # Pequeña pausa para no sobrecargar la API time.sleep(1) + + # Procesar fullstack al final si está en la lista + if fullstack_type: + rate_file = RATES_DIR / f"{fullstack_type}.rate" + + # Si el archivo ya existe y no estamos forzando la actualización, saltamos + if rate_file.exists() and not force_update: + # Leer el valor para mostrarlo + try: + with open(rate_file, 'r', encoding='utf-8') as f: + fullstack_rate = float(f.read().strip()) + logger.info(f"El archivo {rate_file} ya existe con valor {fullstack_rate:.2f}. Saltando.") + except (FileNotFoundError, ValueError) as e: + logger.warning(f"Error al leer archivo {rate_file}: {e}") + return + + # Primero calculamos el valor más alto entre todos los tipos + max_rate_value = 0.0 + for prog_type, rate_value in rates_dict.items(): + if prog_type != 'fullstack' and rate_value > max_rate_value: + max_rate_value = rate_value + + logger.info(f"Valor más alto encontrado: {max_rate_value:.2f}") + + # Obtener tarifa para fullstack vía API + api_rate = None + if api_available: + prompt = generate_prompt_base(fullstack_type) + logger.info(f"Consultando tarifa para {fullstack_type}") + + try: + # Consultar a Perplexity + api_rate = query_perplexity(prompt, model) + + if api_rate is not None: + logger.info(f"Tarifa obtenida correctamente: {api_rate:.2f}") + else: + logger.error(f"No se pudo obtener la tarifa para {fullstack_type}") + except Exception as e: + logger.error(f"Error al consultar tarifa para {fullstack_type}: {e}") + + # Si la API falló, usar el valor predeterminado + if api_rate is None: + logger.warning(f"Usando valor predeterminado para {fullstack_type}") + api_rate = get_default_rate(fullstack_type) + logger.info(f"Valor predeterminado: {api_rate:.2f}") + + # Calcular el valor de fullstack + # Si el valor de la API es menor o igual al valor más alto, usar 1.5 veces el valor más alto + if api_rate <= max_rate_value: + fullstack_rate = 1.5 * max_rate_value + logger.info(f"API rate ({api_rate:.2f}) <= max rate ({max_rate_value:.2f}), ajustando fullstack a 1.5 * {max_rate_value:.2f} = {fullstack_rate:.2f}") + else: + fullstack_rate = api_rate + logger.info(f"API rate ({api_rate:.2f}) > max rate ({max_rate_value:.2f}), manteniendo valor API") + + # Limitar a tarifas menores de 200 USD/hora + max_limit = 200.00 + if fullstack_rate > max_limit: + logger.warning(f"Ajustando tarifa {fullstack_rate:.2f} al máximo permitido de {max_limit}") + fullstack_rate = max_limit + + # Guardar el resultado en el archivo + with open(rate_file, 'w', encoding='utf-8') as f: + f.write(f"{fullstack_rate:.2f}") + + # Mostrar el resultado en la consola + result_message = f"Tarifa para {fullstack_type}: {fullstack_rate:.2f} USD/hora" + logger.info(f"{'Actualizado' if force_update and rate_file.exists() else 'Creado'} archivo {rate_file} con valor: {fullstack_rate:.2f}") + show_result(result_message) def generate_prompt_base(programmer_type): """