- Reemplazada expresión de versión dinámica por valor estático 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
343 lines
11 KiB
Bash
Executable file
343 lines
11 KiB
Bash
Executable file
#!/bin/bash
|
|
#Script : sora.sh
|
|
#Apps : MRDEVS TOOLS
|
|
#Description : Ejecuta aider con configuración de OpenRouter/Ollama
|
|
#Author : Sora Rosero One <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 : 1.3.1
|
|
#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. <mauro@rosero.one>]
|
|
#==============================================================================
|
|
# 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.
|
|
#
|
|
# 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 <https://www.gnu.org/licenses/>.
|
|
|
|
# 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
|
|
|
|
# Mensaje de bienvenida
|
|
echo "=== Sora - Asistente de Desarrollo Colaborativo ==="
|
|
echo "Versión: $VERSION"
|
|
echo ""
|
|
|
|
# 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
|
|
}
|
|
|
|
# Obtener ruta de tokens
|
|
get_tokens_path() {
|
|
local tokens_path_file="$SCRIPT_DIR/$BIN_CFGS/ai_tokens.path"
|
|
local tokens_path
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
echo -n "Rendimiento esperado: "
|
|
case "$level" in
|
|
"Muy Malo")
|
|
gum style --foreground 255 --background 1 " Muy Malo "
|
|
;;
|
|
"Malo")
|
|
gum style --foreground 255 --background 1 " Malo "
|
|
;;
|
|
"Pobre")
|
|
gum style --foreground 255 --background 202 " Pobre "
|
|
;;
|
|
"Intermedio")
|
|
gum style --foreground 255 --background 3 " Intermedio "
|
|
;;
|
|
"Bueno")
|
|
gum style --foreground 255 --background 35 " Bueno "
|
|
;;
|
|
"Muy Bueno")
|
|
gum style --foreground 255 --background 2 " Muy Bueno "
|
|
;;
|
|
"Excelente")
|
|
gum style --foreground 255 --background 5 " Excelente "
|
|
;;
|
|
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"
|
|
|
|
# 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
|
|
|
|
# Iniciar Ollama si es necesario
|
|
start_ollama
|
|
OLLAMA_STARTED=$?
|
|
|
|
# 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
|
|
|
|
# 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"
|
|
|
|
# Seleccionar modelo
|
|
SELECTED_MODEL=$(select_ollama_model)
|
|
if [ -z "$SELECTED_MODEL" ]; then
|
|
exit 1
|
|
fi
|
|
|
|
echo "Modelo seleccionado: $SELECTED_MODEL"
|
|
|
|
# Añadir prefijo
|
|
OLLAMA_FULL_MODEL="ollama_chat/$SELECTED_MODEL"
|
|
echo "Modelo con prefijo: $OLLAMA_FULL_MODEL"
|
|
|
|
# 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" -eq 0 ]; then
|
|
echo "Deteniendo Ollama..."
|
|
"$SCRIPT_DIR/ollama_down.sh"
|
|
fi
|
|
}
|
|
|
|
# Ejecución principal según el modo seleccionado
|
|
if [[ "$MODE" == "Local (Ollama)" ]]; then
|
|
run_local_aider "$@"
|
|
else
|
|
run_remote_aider "$@"
|
|
fi
|