diff --git a/bin/sora.sh b/bin/sora.sh index d8046ce..cb94036 100755 --- a/bin/sora.sh +++ b/bin/sora.sh @@ -1,104 +1,232 @@ #!/bin/bash -# [Author] Cortana Rosero One -# [Generated] Created by Claude Code (claude-3-7-sonnet-20250219) -# Modified Date: 2025-04-07 -# Version $(cat "$(dirname "$0")/config/version" 2>/dev/null || echo "1.0.0") +#Script : sora.sh +#Apps : MRDEVS TOOLS +#Description : Ejecuta aider con configuración de OpenRouter/Ollama +#Author : Sora Rosero One +#Generated by : Claude Code (claude-3-7-sonnet-20250219) +#Created : 2025/04/07 10:23:45 +#Modified : 2025/04/07 12:10:30 +#Version : $(cat "$(dirname "$0")/config/version" 2>/dev/null || echo "1.0.0") +#Use Notes : +# Conecta con modelos de IA remotos (OpenRouter) o locales (Ollama) +# Evalúa el hardware para ejecución local y muestra diagnóstico +# Permite selección interactiva de modelos con gum +#============================================================================== +# Derechos de Autor [2025] [Mauro Rosero P. ] +#============================================================================== +# Este programa es software libre: usted puede redistribuirlo y/o modificarlo +# bajo los términos de la Licencia Pública Affero General de GNU tal como +# lo publica la Free Software Foundation, ya sea la versión 3 de la licencia, +# o (a su elección) cualquier versión posterior. # -# Description: Script para ejecutar aider con la configuración adecuada de OpenRouter -# Usage: ./sora.sh [parámetros para aider] +# Este programa se distribuye con la esperanza de que sea útil, +# pero SIN NINGUNA GARANTÍA; sin siquiera la garantía implícita de +# COMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Consulte la +# Licencia Pública Affero General de GNU para obtener más detalles. +# +# Debería haber recibido una copia de la Licencia Pública Affero General +# junto con este programa. Si no la recibió, consulte . -# Verifica si aider está instalado -if ! command -v aider &> /dev/null; then - echo "Error: aider no está instalado." - echo "Instálelo ejecutando: bin/sora_install.sh" +# Configuración inicial +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BIN_BASE="bin" +BIN_LIBS="lib" +BIN_MESG="msg" +BIN_CFGS="config" +BIN_SOPS="sops" + +# Cargar bibliotecas +if [ -f "$SCRIPT_DIR/../$BIN_LIBS/base.lib" ]; then + source "$SCRIPT_DIR/../$BIN_LIBS/base.lib" +else + echo "Error: No se pudo cargar la biblioteca base." exit 1 fi -# Obtiene la ruta base de tokens desde el archivo de configuración -TOKENS_BASE_PATH=$(cat "$(dirname "$0")/config/ai_tokens.path" 2>/dev/null) -if [ -z "$TOKENS_BASE_PATH" ]; then - echo "Error: No se pudo obtener la ruta base de tokens." - exit 1 -fi +# Mensaje de bienvenida +echo "=== Sora - Asistente de Desarrollo Colaborativo ===" +echo "Versión: $VERSION" +echo "" -# Expande la ruta si comienza con ~ -if [[ "$TOKENS_BASE_PATH" == "~"* ]]; then - TOKENS_BASE_PATH="${TOKENS_BASE_PATH/#\~/$HOME}" -fi +# Verificar si aider está instalado +check_aider() { + if ! command -v aider &> /dev/null; then + echo "Error: aider no está instalado." + echo "Instálelo ejecutando: $BIN_BASE/sora_install.sh" + exit 1 + fi +} -# Define el archivo de tokens de OpenRouter -OPENROUTER_TOKEN_FILE="${TOKENS_BASE_PATH}/router.sops.yaml" - -# Verifica si el archivo de token existe -if [ ! -f "$OPENROUTER_TOKEN_FILE" ]; then - echo "Error: Archivo de token no encontrado: $OPENROUTER_TOKEN_FILE" - echo "Registre su token usando ai_token.sh o solicite el token al administrador del proyecto." - exit 1 -fi - -# Desencripta y obtiene el token de OpenRouter (decodificando base64) -OPENROUTER_API_KEY=$(sops -d "$OPENROUTER_TOKEN_FILE" | cut -d\| -f2 | tr -d '[:space:]' | base64 -d) -if [ -z "$OPENROUTER_API_KEY" ]; then - echo "Error: No se pudo desencriptar el token de OpenRouter." - exit 1 -fi - -# Lee o crea el archivo de configuración de la API base -API_BASE_CONFIG_FILE="$(dirname "$0")/config/sora_api_base.cfg" -if [ ! -f "$API_BASE_CONFIG_FILE" ]; then - echo "https://openrouter.ai/api/v1" > "$API_BASE_CONFIG_FILE" -fi -OPENAI_API_BASE=$(cat "$API_BASE_CONFIG_FILE" 2>/dev/null || echo "https://openrouter.ai/api/v1") - -# Lee o crea el archivo de configuración del modelo -MODEL_CONFIG_FILE="$(dirname "$0")/config/sora_model.cfg" -if [ ! -f "$MODEL_CONFIG_FILE" ]; then - echo "deepseek/deepseek-r1-distill-llama-70b:free" > "$MODEL_CONFIG_FILE" -fi -AIDER_MODEL=$(cat "$MODEL_CONFIG_FILE" 2>/dev/null || echo "deepseek/deepseek-r1-distill-llama-70b:free") - -# Pregunta al usuario si desea usar modelo remoto o local (ollama) -MODE=$(gum choose "Remoto (OpenRouter)" "Local (Ollama)") - -if [[ "$MODE" == "Local (Ollama)" ]]; then - # Muestra advertencia sobre rendimiento - echo "⚠️ ADVERTENCIA: El uso de modelos locales requiere hardware adecuado." - echo " Si su hardware no es suficiente, las respuestas pueden ser extremadamente lentas." +# Obtener ruta de tokens +get_tokens_path() { + local tokens_path_file="$SCRIPT_DIR/$BIN_CFGS/ai_tokens.path" + local tokens_path - # Evalúa el hardware de la máquina - CPU_CORES=$(nproc) - RAM_TOTAL_GB=$(free -g | awk '/^Mem:/{print $2}') - RAM_AVAILABLE_GB=$(free -g | awk '/^Mem:/{print $7}') - HAS_GPU=$(lspci | grep -i nvidia | grep -v "Audio\|USB" || echo "") + if [ -f "$tokens_path_file" ]; then + tokens_path=$(cat "$tokens_path_file" 2>/dev/null) + if [ -z "$tokens_path" ]; then + echo "Error: Archivo de configuración de ruta de tokens vacío." + exit 1 + fi + + # Expandir ruta si comienza con ~ + if [[ "$tokens_path" == "~"* ]]; then + tokens_path="${tokens_path/#\~/$HOME}" + fi + + echo "$tokens_path" + else + echo "Error: No se pudo encontrar el archivo de configuración de ruta de tokens." + exit 1 + fi +} + +# Ejecutar verificaciones iniciales +check_aider +TOKENS_BASE_PATH=$(get_tokens_path) + +# Función para verificar y obtener tokens +check_token() { + local token_file=$1 + local provider=$2 - # Determina nivel de rendimiento - PERFORMANCE_LEVEL="Muy Malo" - if [ -n "$HAS_GPU" ] && [ $CPU_CORES -ge 8 ] && [ $RAM_AVAILABLE_GB -ge 16 ]; then - PERFORMANCE_LEVEL="Excelente" - elif [ -n "$HAS_GPU" ] && [ $CPU_CORES -ge 6 ] && [ $RAM_AVAILABLE_GB -ge 12 ]; then - PERFORMANCE_LEVEL="Muy Bueno" - elif [ $CPU_CORES -ge 8 ] && [ $RAM_AVAILABLE_GB -ge 12 ]; then - PERFORMANCE_LEVEL="Bueno" - elif [ $CPU_CORES -ge 6 ] && [ $RAM_AVAILABLE_GB -ge 8 ]; then - PERFORMANCE_LEVEL="Intermedio" - elif [ $CPU_CORES -ge 4 ] && [ $RAM_AVAILABLE_GB -ge 6 ]; then - PERFORMANCE_LEVEL="Pobre" - elif [ $CPU_CORES -ge 2 ] && [ $RAM_AVAILABLE_GB -ge 4 ]; then - PERFORMANCE_LEVEL="Malo" + if [ ! -f "$token_file" ]; then + echo "Error: Archivo de token no encontrado: $token_file" + echo "Registre su token usando $BIN_BASE/ai_token.sh o solicite el token al administrador del proyecto." + exit 1 fi - # Muestra estado del hardware - echo "" - echo "Evaluación de hardware:" - echo "- CPU Cores: $CPU_CORES" - echo "- RAM Total: $RAM_TOTAL_GB GB" - echo "- RAM Disponible: $RAM_AVAILABLE_GB GB" - echo "- GPU NVIDIA: $([ -n "$HAS_GPU" ] && echo "Detectada" || echo "No detectada")" + local api_key + api_key=$(sops -d "$token_file" | cut -d\| -f2 | tr -d '[:space:]' | base64 -d) + + if [ -z "$api_key" ]; then + echo "Error: No se pudo desencriptar el token de $provider." + exit 1 + fi + + echo "$api_key" +} + +# Función para cargar o crear configuración +load_config() { + local config_file=$1 + local default_value=$2 + local description=$3 + + if [ ! -f "$config_file" ]; then + echo "Creando archivo de configuración para $description..." + echo "$default_value" > "$config_file" + fi + + local config_value + config_value=$(cat "$config_file" 2>/dev/null || echo "$default_value") + + echo "$config_value" +} + +# Función para evaluar hardware +evaluate_hardware() { + local cpu_cores=$(nproc) + local ram_total_gb=$(free -g | awk '/^Mem:/{print $2}') + local ram_available_gb=$(free -g | awk '/^Mem:/{print $7}') + local has_gpu=$(lspci | grep -i nvidia | grep -v "Audio\|USB" || echo "") + + echo "CPU Cores: $cpu_cores" + echo "RAM Total: $ram_total_gb GB" + echo "RAM Disponible: $ram_available_gb GB" + echo "GPU NVIDIA: $([ -n "$has_gpu" ] && echo "Detectada" || echo "No detectada")" + + # Determinar nivel de rendimiento + local performance_level="Muy Malo" + if [ -n "$has_gpu" ] && [ $cpu_cores -ge 8 ] && [ $ram_available_gb -ge 16 ]; then + performance_level="Excelente" + elif [ -n "$has_gpu" ] && [ $cpu_cores -ge 6 ] && [ $ram_available_gb -ge 12 ]; then + performance_level="Muy Bueno" + elif [ $cpu_cores -ge 8 ] && [ $ram_available_gb -ge 12 ]; then + performance_level="Bueno" + elif [ $cpu_cores -ge 6 ] && [ $ram_available_gb -ge 8 ]; then + performance_level="Intermedio" + elif [ $cpu_cores -ge 4 ] && [ $ram_available_gb -ge 6 ]; then + performance_level="Pobre" + elif [ $cpu_cores -ge 2 ] && [ $ram_available_gb -ge 4 ]; then + performance_level="Malo" + fi + + echo "$performance_level" +} + +# Definir archivos de configuración +OPENROUTER_TOKEN_FILE="${TOKENS_BASE_PATH}/router.sops.yaml" +API_BASE_CONFIG_FILE="$SCRIPT_DIR/$BIN_CFGS/sora_api_base.cfg" +MODEL_CONFIG_FILE="$SCRIPT_DIR/$BIN_CFGS/sora_model.cfg" + +# Cargar configuraciones +OPENAI_API_BASE=$(load_config "$API_BASE_CONFIG_FILE" "https://openrouter.ai/api/v1" "API base") +AIDER_MODEL=$(load_config "$MODEL_CONFIG_FILE" "deepseek/deepseek-r1-distill-llama-70b:free" "modelo predeterminado") + +# Verificar si gum está instalado +if ! command -v gum &> /dev/null; then + echo "Error: gum no está instalado." + echo "Instálelo ejecutando: $BIN_BASE/bootstrap.sh" + exit 1 +fi + +# Preguntar al usuario por el modo a usar +MODE=$(gum choose "Remoto (OpenRouter)" "Local (Ollama)") + +# Función para iniciar y comprobar Ollama +start_ollama() { + # Verifica si ollama está activo + if ! curl -s http://127.0.0.1:11434/api/tags >/dev/null 2>&1; then + echo "Ollama no está activo. Iniciando..." + "$SCRIPT_DIR/ollama_up.sh" + + # Espera hasta 30 segundos para que Ollama se inicie completamente + local wait_time=0 + local max_wait=30 + while ! curl -s http://127.0.0.1:11434/api/tags >/dev/null 2>&1; do + if [ $wait_time -ge $max_wait ]; then + echo "Error: No se pudo iniciar Ollama después de $max_wait segundos." + return 1 + fi + echo "Esperando que Ollama responda... ($wait_time/$max_wait)" + sleep 1 + wait_time=$((wait_time + 1)) + done + return 0 + fi + return 2 # Ya estaba activo +} + +# Función para seleccionar modelo de Ollama +select_ollama_model() { + echo "Consultando modelos disponibles en Ollama..." + local models + models=$(curl -s http://127.0.0.1:11434/api/tags | jq -r '.models[].name') + + if [ -z "$models" ]; then + echo "Error: No se encontraron modelos en Ollama." + return 1 + fi + + echo "Seleccione un modelo:" + local selected + selected=$(echo "$models" | gum filter --placeholder="Buscar modelo...") + + if [ -z "$selected" ]; then + echo "No se seleccionó ningún modelo." + return 1 + fi + + echo "$selected" +} + +# Función para mostrar valoración de rendimiento +show_performance_rating() { + local level=$1 - # Muestra barra de rendimiento con gum - echo "" echo -n "Rendimiento esperado: " - case "$PERFORMANCE_LEVEL" in + case "$level" in "Muy Malo") gum style --foreground 255 --background 1 " Muy Malo " ;; @@ -122,76 +250,94 @@ if [[ "$MODE" == "Local (Ollama)" ]]; then ;; esac echo "" +} + +# Función para ejecutar aider en modo remoto +run_remote_aider() { + echo "Modo: Remoto (OpenRouter)" + echo "Modelo: $AIDER_MODEL" + echo "API Base: $OPENAI_API_BASE" - # Pregunta si desea continuar + # Verificar y obtener token de OpenRouter + OPENROUTER_API_KEY=$(check_token "$OPENROUTER_TOKEN_FILE" "OpenRouter") + + # Ejecutar aider + OPENAI_API_BASE="$OPENAI_API_BASE" OPENROUTER_API_KEY="$OPENROUTER_API_KEY" AIDER_MODEL="$AIDER_MODEL" aider --no-git --no-show-model-warnings "$@" +} + +# Función para ejecutar aider en modo local +run_local_aider() { + echo "Modo: Local (Ollama)" + + # Mostrar advertencia sobre rendimiento + echo "⚠️ ADVERTENCIA: El uso de modelos locales requiere hardware adecuado." + echo " Si su hardware no es suficiente, las respuestas pueden ser extremadamente lentas." + + # Evaluar hardware y mostrar información + echo "" + echo "Evaluación de hardware:" + + # Obtener datos de rendimiento + HARDWARE_INFO=$(evaluate_hardware) + # Extraer líneas individuales + readarray -t hardware_lines <<< "$HARDWARE_INFO" + + # Mostrar información de hardware + for ((i=0; i<${#hardware_lines[@]}-1; i++)); do + echo "- ${hardware_lines[i]}" + done + + # Mostrar valoración de rendimiento (última línea) + echo "" + show_performance_rating "${hardware_lines[${#hardware_lines[@]}-1]}" + + # Confirmar si desea continuar if ! gum confirm "¿Desea continuar con el modo local?"; then echo "Operación cancelada por el usuario." exit 0 fi - # Verifica si ollama está activo - if ! curl -s http://127.0.0.1:11434/api/tags >/dev/null 2>&1; then - echo "Ollama no está activo. Iniciando..." - "$(dirname "$0")/ollama_up.sh" - - # Espera hasta 30 segundos para que Ollama se inicie completamente - WAIT_TIME=0 - MAX_WAIT=30 - while ! curl -s http://127.0.0.1:11434/api/tags >/dev/null 2>&1; do - if [ $WAIT_TIME -ge $MAX_WAIT ]; then - echo "Error: No se pudo iniciar Ollama después de $MAX_WAIT segundos." - exit 1 - fi - echo "Esperando que Ollama responda... ($WAIT_TIME/$MAX_WAIT)" - sleep 1 - WAIT_TIME=$((WAIT_TIME + 1)) - done - OLLAMA_STARTED=true - fi + # Iniciar Ollama si es necesario + start_ollama + OLLAMA_STARTED=$? - # Verifica que Ollama funcione correctamente haciendo una solicitud simple + # Verificar que Ollama funcione correctamente echo "Verificando que Ollama responda correctamente..." if ! curl -s http://127.0.0.1:11434/api/tags | jq -e '.models' >/dev/null 2>&1; then echo "Error: Ollama está iniciado pero no responde correctamente." exit 1 fi - # Configura para usar Ollama - OLLAMA_API_BASE=$(cat "$(dirname "$0")/config/ollama.local" 2>/dev/null) + # Cargar API base + OLLAMA_CONFIG_FILE="$SCRIPT_DIR/$BIN_CFGS/ollama.local" + OLLAMA_API_BASE=$(cat "$OLLAMA_CONFIG_FILE" 2>/dev/null) echo "Usando Ollama con API base: $OLLAMA_API_BASE" - # Lista y permite seleccionar modelos disponibles en Ollama - echo "Consultando modelos disponibles en Ollama..." - OLLAMA_MODELS=$(curl -s http://127.0.0.1:11434/api/tags | jq -r '.models[].name') - if [ -z "$OLLAMA_MODELS" ]; then - echo "Error: No se encontraron modelos en Ollama." - exit 1 - fi - - # Permite seleccionar un modelo utilizando gum - echo "Seleccione un modelo:" - SELECTED_MODEL=$(echo "$OLLAMA_MODELS" | gum filter --placeholder="Buscar modelo...") - + # Seleccionar modelo + SELECTED_MODEL=$(select_ollama_model) if [ -z "$SELECTED_MODEL" ]; then - echo "No se seleccionó ningún modelo. Saliendo." exit 1 fi echo "Modelo seleccionado: $SELECTED_MODEL" - # Añade el prefijo al modelo de Ollama + # Añadir prefijo OLLAMA_FULL_MODEL="ollama_chat/$SELECTED_MODEL" echo "Modelo con prefijo: $OLLAMA_FULL_MODEL" - # Ejecuta aider con la configuración de Ollama + # Ejecutar aider OLLAMA_API_BASE="$OLLAMA_API_BASE" AIDER_MODEL="$OLLAMA_FULL_MODEL" aider --no-git --no-show-model-warnings "$@" # Si iniciamos Ollama, lo detenemos al finalizar - if [ "$OLLAMA_STARTED" = true ]; then + if [ "$OLLAMA_STARTED" -eq 0 ]; then echo "Deteniendo Ollama..." - "$(dirname "$0")/ollama_down.sh" + "$SCRIPT_DIR/ollama_down.sh" fi +} + +# Ejecución principal según el modo seleccionado +if [[ "$MODE" == "Local (Ollama)" ]]; then + run_local_aider "$@" else - # Ejecuta aider con la configuración de OpenRouter - OPENAI_API_BASE="$OPENAI_API_BASE" OPENROUTER_API_KEY="$OPENROUTER_API_KEY" AIDER_MODEL="$AIDER_MODEL" aider --no-git --no-show-model-warnings "$@" + run_remote_aider "$@" fi