atareao revisou este gist 4 hours ago. Ir para a revisão
1 file changed, 386 insertions
init-lab.sh(arquivo criado)
| @@ -0,0 +1,386 @@ | |||
| 1 | + | #!/bin/bash | |
| 2 | + | # ============================================================================= | |
| 3 | + | # init-lab.sh — Inicialización del laboratorio de IA local | |
| 4 | + | # ============================================================================= | |
| 5 | + | # | |
| 6 | + | # Uso: | |
| 7 | + | # chmod +x init-lab.sh | |
| 8 | + | # ./init-lab.sh | |
| 9 | + | # | |
| 10 | + | # Descripción: | |
| 11 | + | # Script de inicialización rápida del laboratorio. Crea la estructura de | |
| 12 | + | # directorios recomendada en el episodio, descarga los modelos esenciales | |
| 13 | + | # y genera un docker-compose.yml básico para empezar. | |
| 14 | + | # | |
| 15 | + | # Este script está diseñado para que el oyente pueda poner en marcha su | |
| 16 | + | # laboratorio con un solo comando después de instalar Ollama y Docker. | |
| 17 | + | # | |
| 18 | + | # Estructura que crea: | |
| 19 | + | # ~/lab-ia/ | |
| 20 | + | # ├── docker/ | |
| 21 | + | # │ ├── ollama/ | |
| 22 | + | # │ ├── open-webui/ | |
| 23 | + | # │ └── docker-compose.yml | |
| 24 | + | # ├── modelos/ | |
| 25 | + | # ├── datos/ | |
| 26 | + | # │ ├── notas/ | |
| 27 | + | # │ ├── transcripciones/ | |
| 28 | + | # │ └── embeddings/ | |
| 29 | + | # ├── scripts/ | |
| 30 | + | # └── config/ | |
| 31 | + | # ├── ollama/ | |
| 32 | + | # └── open-webui/ | |
| 33 | + | # | |
| 34 | + | # Requisitos: | |
| 35 | + | # - Ollama instalado (ver 02-instalacion/setup-ollama.sh) | |
| 36 | + | # - Docker instalado (para el docker-compose.yml) | |
| 37 | + | # - Conexión a internet (para descargar modelos) | |
| 38 | + | # - ~5 GB de espacio libre | |
| 39 | + | # | |
| 40 | + | # ============================================================================= | |
| 41 | + | ||
| 42 | + | set -euo pipefail | |
| 43 | + | ||
| 44 | + | # Colores | |
| 45 | + | VERDE='\033[0;32m' | |
| 46 | + | AMARILLO='\033[1;33m' | |
| 47 | + | AZUL='\033[0;34m' | |
| 48 | + | ROJO='\033[0;31m' | |
| 49 | + | RESET='\033[0m' | |
| 50 | + | ||
| 51 | + | # Directorio base del laboratorio | |
| 52 | + | LAB_DIR="$HOME/lab-ia" | |
| 53 | + | ||
| 54 | + | echo -e "${AZUL}╔══════════════════════════════════════════════════════╗${RESET}" | |
| 55 | + | echo -e "${AZUL}║ 🔬 Inicialización del Laboratorio de IA Local ║${RESET}" | |
| 56 | + | echo -e "${AZUL}║ Episodio 827 — Recursos IA: el botiquín del ║${RESET}" | |
| 57 | + | echo -e "${AZUL}║ explorador ║${RESET}" | |
| 58 | + | echo -e "${AZUL}╚══════════════════════════════════════════════════════╝${RESET}" | |
| 59 | + | echo "" | |
| 60 | + | ||
| 61 | + | # ============================================================================= | |
| 62 | + | # PASO 1: Comprobar requisitos | |
| 63 | + | # ============================================================================= | |
| 64 | + | echo -e "${AZUL}[1/5] Comprobando requisitos...${RESET}" | |
| 65 | + | echo "" | |
| 66 | + | ||
| 67 | + | REQUISITOS_OK=true | |
| 68 | + | ||
| 69 | + | # Ollama | |
| 70 | + | echo -n " Ollama: " | |
| 71 | + | if command -v ollama &>/dev/null; then | |
| 72 | + | echo -e "${VERDE}✓${RESET}" | |
| 73 | + | else | |
| 74 | + | echo -e "${ROJO}✗${RESET}" | |
| 75 | + | echo " → Instala Ollama primero: curl -fsSL https://ollama.com/install.sh | sh" | |
| 76 | + | REQUISITOS_OK=false | |
| 77 | + | fi | |
| 78 | + | ||
| 79 | + | # Docker | |
| 80 | + | echo -n " Docker: " | |
| 81 | + | if command -v docker &>/dev/null; then | |
| 82 | + | echo -e "${VERDE}✓${RESET}" | |
| 83 | + | else | |
| 84 | + | echo -e "${AMARILLO}⚠${RESET}" | |
| 85 | + | echo " → Docker no está instalado. El docker-compose.yml se creará igual." | |
| 86 | + | echo " → Instálalo con: curl -fsSL https://get.docker.com | sh" | |
| 87 | + | fi | |
| 88 | + | ||
| 89 | + | # Espacio en disco (~5 GB necesarios) | |
| 90 | + | echo -n " Espacio en disco: " | |
| 91 | + | ESPACIO_LIBRE=$(df -BG "$HOME" | tail -1 | awk '{print $4}' | sed 's/G//') | |
| 92 | + | if [ "$ESPACIO_LIBRE" -ge 10 ]; then | |
| 93 | + | echo -e "${VERDE}✓${RESET} ($ESPACIO_LIBRE GB libres)" | |
| 94 | + | elif [ "$ESPACIO_LIBRE" -ge 5 ]; then | |
| 95 | + | echo -e "${AMARILLO}⚠${RESET} ($ESPACIO_LIBRE GB libres — suficiente pero justo)" | |
| 96 | + | else | |
| 97 | + | echo -e "${ROJO}✗${RESET} ($ESPACIO_LIBRE GB libres — necesitas al menos 5 GB)" | |
| 98 | + | REQUISITOS_OK=false | |
| 99 | + | fi | |
| 100 | + | ||
| 101 | + | echo "" | |
| 102 | + | ||
| 103 | + | if [ "$REQUISITOS_OK" = false ]; then | |
| 104 | + | echo " ERROR: Requisitos insuficientes. Revisa los mensajes anteriores." | |
| 105 | + | exit 1 | |
| 106 | + | fi | |
| 107 | + | ||
| 108 | + | # ============================================================================= | |
| 109 | + | # PASO 2: Crear estructura de directorios | |
| 110 | + | # ============================================================================= | |
| 111 | + | echo -e "${AZUL}[2/5] Creando estructura de directorios...${RESET}" | |
| 112 | + | echo "" | |
| 113 | + | ||
| 114 | + | mkdir -p "$LAB_DIR" | |
| 115 | + | mkdir -p "$LAB_DIR/docker/ollama" | |
| 116 | + | mkdir -p "$LAB_DIR/docker/open-webui" | |
| 117 | + | mkdir -p "$LAB_DIR/modelos" | |
| 118 | + | mkdir -p "$LAB_DIR/datos/notas" | |
| 119 | + | mkdir -p "$LAB_DIR/datos/transcripciones" | |
| 120 | + | mkdir -p "$LAB_DIR/datos/embeddings" | |
| 121 | + | mkdir -p "$LAB_DIR/scripts" | |
| 122 | + | mkdir -p "$LAB_DIR/config/ollama" | |
| 123 | + | mkdir -p "$LAB_DIR/config/open-webui" | |
| 124 | + | ||
| 125 | + | echo " Estructura creada en: ${AZUL}${LAB_DIR}${RESET}" | |
| 126 | + | echo "" | |
| 127 | + | echo " ${LAB_DIR}/" | |
| 128 | + | echo " ├── docker/" | |
| 129 | + | echo " │ ├── ollama/" | |
| 130 | + | echo " │ ├── open-webui/" | |
| 131 | + | echo " │ └── docker-compose.yml (se crea a continuación)" | |
| 132 | + | echo " ├── modelos/" | |
| 133 | + | echo " ├── datos/" | |
| 134 | + | echo " │ ├── notas/" | |
| 135 | + | echo " │ ├── transcripciones/" | |
| 136 | + | echo " │ └── embeddings/" | |
| 137 | + | echo " ├── scripts/" | |
| 138 | + | echo " └── config/" | |
| 139 | + | echo " ├── ollama/" | |
| 140 | + | echo " └── open-webui/" | |
| 141 | + | echo "" | |
| 142 | + | ||
| 143 | + | # ============================================================================= | |
| 144 | + | # PASO 3: Crear docker-compose.yml básico | |
| 145 | + | # ============================================================================= | |
| 146 | + | echo -e "${AZUL}[3/5] Creando docker-compose.yml básico...${RESET}" | |
| 147 | + | echo "" | |
| 148 | + | ||
| 149 | + | COMPOSE_FILE="$LAB_DIR/docker/docker-compose.yml" | |
| 150 | + | ||
| 151 | + | cat > "$COMPOSE_FILE" << 'COMPOSE_EOF' | |
| 152 | + | # ============================================================================= | |
| 153 | + | # docker-compose.yml — Laboratorio IA Local | |
| 154 | + | # Generado por init-lab.sh del Episodio 827 | |
| 155 | + | # ============================================================================= | |
| 156 | + | # | |
| 157 | + | # Uso: | |
| 158 | + | # docker compose up -d # Levantar todos los servicios | |
| 159 | + | # docker compose down # Detener todos los servicios | |
| 160 | + | # docker compose logs -f # Ver logs en tiempo real | |
| 161 | + | # | |
| 162 | + | # Servicios: | |
| 163 | + | # - ollama: Gestor de modelos de lenguaje (API en :11434) | |
| 164 | + | # - open-webui: Interfaz gráfica web (web en :3000) | |
| 165 | + | # | |
| 166 | + | # Requisitos: | |
| 167 | + | # - Docker Engine 24+ o Podman 4+ | |
| 168 | + | # - Docker Compose v2+ | |
| 169 | + | # | |
| 170 | + | # ============================================================================= | |
| 171 | + | ||
| 172 | + | services: | |
| 173 | + | # --------------------------------------------------------------------------- | |
| 174 | + | # Ollama — Gestor de modelos de lenguaje | |
| 175 | + | # --------------------------------------------------------------------------- | |
| 176 | + | ollama: | |
| 177 | + | image: ollama/ollama:latest | |
| 178 | + | container_name: ollama-server | |
| 179 | + | hostname: ollama | |
| 180 | + | volumes: | |
| 181 | + | # Persistencia de modelos descargados | |
| 182 | + | - ./ollama/models:/root/.ollama | |
| 183 | + | ports: | |
| 184 | + | # API REST de Ollama | |
| 185 | + | - "11434:11434" | |
| 186 | + | environment: | |
| 187 | + | # Mantener el modelo en memoria para respuestas más rápidas | |
| 188 | + | - OLLAMA_KEEP_ALIVE=5m | |
| 189 | + | # Número máximo de modelos cargados simultáneamente | |
| 190 | + | - OLLAMA_NUM_PARALLEL=1 | |
| 191 | + | # Límite de contexto (ventana de tokens) | |
| 192 | + | - OLLAMA_CONTEXT_LENGTH=8192 | |
| 193 | + | restart: unless-stopped | |
| 194 | + | healthcheck: | |
| 195 | + | test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] | |
| 196 | + | interval: 30s | |
| 197 | + | timeout: 10s | |
| 198 | + | retries: 3 | |
| 199 | + | start_period: 40s | |
| 200 | + | networks: | |
| 201 | + | - ia-local-net | |
| 202 | + | ||
| 203 | + | # --------------------------------------------------------------------------- | |
| 204 | + | # Open WebUI — Interfaz gráfica para chatear con modelos | |
| 205 | + | # --------------------------------------------------------------------------- | |
| 206 | + | open-webui: | |
| 207 | + | image: ghcr.io/open-webui/open-webui:main | |
| 208 | + | container_name: open-webui | |
| 209 | + | depends_on: | |
| 210 | + | ollama: | |
| 211 | + | condition: service_healthy | |
| 212 | + | volumes: | |
| 213 | + | # Persistencia de conversaciones, configuraciones, archivos subidos | |
| 214 | + | - ./open-webui/data:/app/backend/data | |
| 215 | + | ports: | |
| 216 | + | # Interfaz web | |
| 217 | + | - "3000:8080" | |
| 218 | + | environment: | |
| 219 | + | # URL del servicio Ollama (nombre del contenedor, no localhost) | |
| 220 | + | - OLLAMA_BASE_URL=http://ollama:11434 | |
| 221 | + | # Tiempo máximo de espera para respuestas largas | |
| 222 | + | - WEBUI_TIMEOUT=300 | |
| 223 | + | restart: unless-stopped | |
| 224 | + | healthcheck: | |
| 225 | + | test: ["CMD", "curl", "-f", "http://localhost:8080/health"] | |
| 226 | + | interval: 30s | |
| 227 | + | timeout: 10s | |
| 228 | + | retries: 3 | |
| 229 | + | start_period: 60s | |
| 230 | + | networks: | |
| 231 | + | - ia-local-net | |
| 232 | + | ||
| 233 | + | # --------------------------------------------------------------------------- | |
| 234 | + | # Redes | |
| 235 | + | # --------------------------------------------------------------------------- | |
| 236 | + | networks: | |
| 237 | + | ia-local-net: | |
| 238 | + | name: ia-local-network | |
| 239 | + | driver: bridge | |
| 240 | + | COMPOSE_EOF | |
| 241 | + | ||
| 242 | + | echo -e " ${VERDE}✓${RESET} docker-compose.yml creado en:" | |
| 243 | + | echo " $COMPOSE_FILE" | |
| 244 | + | echo "" | |
| 245 | + | ||
| 246 | + | # ============================================================================= | |
| 247 | + | # PASO 4: Descargar modelos esenciales | |
| 248 | + | # ============================================================================= | |
| 249 | + | echo -e "${AZUL}[4/5] Descargando modelos esenciales...${RESET}" | |
| 250 | + | echo "" | |
| 251 | + | ||
| 252 | + | # Modelo de lenguaje pequeño (ideal para empezar) | |
| 253 | + | MODELO_LENGUAJE="qwen2.5:3b" | |
| 254 | + | echo " Modelo de lenguaje: ${AMARILLO}${MODELO_LENGUAJE}${RESET}" | |
| 255 | + | echo " (~2 GB — recomendado para empezar)" | |
| 256 | + | echo "" | |
| 257 | + | ||
| 258 | + | if ollama list 2>/dev/null | grep -q "^${MODELO_LENGUAJE}\s"; then | |
| 259 | + | echo -e " ${VERDE}✓${RESET} ${MODELO_LENGUAJE} ya está descargado." | |
| 260 | + | else | |
| 261 | + | echo " Descargando ${MODELO_LENGUAJE}..." | |
| 262 | + | echo " (Esto puede tardar según tu conexión)" | |
| 263 | + | ollama pull "$MODELO_LENGUAJE" | |
| 264 | + | echo -e " ${VERDE}✓${RESET} ${MODELO_LENGUAJE} descargado." | |
| 265 | + | fi | |
| 266 | + | echo "" | |
| 267 | + | ||
| 268 | + | # Modelo de embeddings (para RAG y búsqueda semántica) | |
| 269 | + | MODELO_EMBED="nomic-embed-text" | |
| 270 | + | echo " Modelo de embeddings: ${AMARILLO}${MODELO_EMBED}${RESET}" | |
| 271 | + | echo " (~0.3 GB — necesario para RAG y búsqueda semántica)" | |
| 272 | + | echo "" | |
| 273 | + | ||
| 274 | + | if ollama list 2>/dev/null | grep -q "^${MODELO_EMBED}\s"; then | |
| 275 | + | echo -e " ${VERDE}✓${RESET} ${MODELO_EMBED} ya está descargado." | |
| 276 | + | else | |
| 277 | + | echo " Descargando ${MODELO_EMBED}..." | |
| 278 | + | ollama pull "$MODELO_EMBED" | |
| 279 | + | echo -e " ${VERDE}✓${RESET} ${MODELO_EMBED} descargado." | |
| 280 | + | fi | |
| 281 | + | echo "" | |
| 282 | + | ||
| 283 | + | # ============================================================================= | |
| 284 | + | # PASO 5: Crear script de respaldo básico | |
| 285 | + | # ============================================================================= | |
| 286 | + | echo -e "${AZUL}[5/5] Creando script de respaldo básico...${RESET}" | |
| 287 | + | echo "" | |
| 288 | + | ||
| 289 | + | BACKUP_SCRIPT="$LAB_DIR/scripts/backup.sh" | |
| 290 | + | ||
| 291 | + | cat > "$BACKUP_SCRIPT" << 'BACKUP_EOF' | |
| 292 | + | #!/bin/bash | |
| 293 | + | # backup.sh — Respaldo del laboratorio de IA local | |
| 294 | + | # | |
| 295 | + | # Uso: | |
| 296 | + | # ./backup.sh # Respaldo completo | |
| 297 | + | # ./backup.sh --modelos # Solo respaldo de modelos | |
| 298 | + | # ./backup.sh --datos # Solo respaldo de datos | |
| 299 | + | # | |
| 300 | + | # Descripción: | |
| 301 | + | # Crea una copia de seguridad de los elementos esenciales del laboratorio: | |
| 302 | + | # modelos descargados, configuraciones y datos generados. | |
| 303 | + | ||
| 304 | + | set -euo pipefail | |
| 305 | + | ||
| 306 | + | BACKUP_DIR="$HOME/lab-ia-backup-$(date +%Y%m%d)" | |
| 307 | + | LAB_DIR="$HOME/lab-ia" | |
| 308 | + | ||
| 309 | + | echo "==============================================" | |
| 310 | + | echo " Respaldo del Laboratorio IA Local" | |
| 311 | + | echo "==============================================" | |
| 312 | + | echo "" | |
| 313 | + | echo " Directorio de respaldo: $BACKUP_DIR" | |
| 314 | + | echo "" | |
| 315 | + | ||
| 316 | + | mkdir -p "$BACKUP_DIR" | |
| 317 | + | ||
| 318 | + | # Respaldar configuración de Ollama | |
| 319 | + | if [ -d "$HOME/.ollama" ]; then | |
| 320 | + | echo " Respaldando modelos de Ollama..." | |
| 321 | + | cp -r "$HOME/.ollama" "$BACKUP_DIR/ollama" | |
| 322 | + | echo " ✓ Modelos respaldados" | |
| 323 | + | fi | |
| 324 | + | ||
| 325 | + | # Respaldar docker-compose y configuraciones | |
| 326 | + | if [ -d "$LAB_DIR/docker" ]; then | |
| 327 | + | echo " Respaldando docker-compose..." | |
| 328 | + | cp -r "$LAB_DIR/docker" "$BACKUP_DIR/docker" | |
| 329 | + | echo " ✓ Configuración Docker respaldada" | |
| 330 | + | fi | |
| 331 | + | ||
| 332 | + | # Respaldar scripts personalizados | |
| 333 | + | if [ -d "$LAB_DIR/scripts" ]; then | |
| 334 | + | echo " Respaldando scripts..." | |
| 335 | + | cp -r "$LAB_DIR/scripts" "$BACKUP_DIR/scripts" | |
| 336 | + | echo " ✓ Scripts respaldados" | |
| 337 | + | fi | |
| 338 | + | ||
| 339 | + | echo "" | |
| 340 | + | echo " Respaldo completado en: $BACKUP_DIR" | |
| 341 | + | echo " Para restaurar: cp -r $BACKUP_DIR/* $HOME/" | |
| 342 | + | echo "==============================================" | |
| 343 | + | BACKUP_EOF | |
| 344 | + | ||
| 345 | + | chmod +x "$BACKUP_SCRIPT" | |
| 346 | + | ||
| 347 | + | echo -e " ${VERDE}✓${RESET} Script de respaldo creado: $BACKUP_SCRIPT" | |
| 348 | + | echo "" | |
| 349 | + | ||
| 350 | + | # ============================================================================= | |
| 351 | + | # CIERRE | |
| 352 | + | # ============================================================================= | |
| 353 | + | echo -e "${VERDE}╔══════════════════════════════════════════════════════╗${RESET}" | |
| 354 | + | echo -e "${VERDE}║ ✅ Laboratorio inicializado con éxito ║${RESET}" | |
| 355 | + | echo -e "${VERDE}╚══════════════════════════════════════════════════════╝${RESET}" | |
| 356 | + | echo "" | |
| 357 | + | echo " Tu laboratorio está listo en: ${AZUL}${LAB_DIR}${RESET}" | |
| 358 | + | echo "" | |
| 359 | + | echo " Modelos descargados:" | |
| 360 | + | ollama list 2>/dev/null | tail -n +2 | while read -r line; do | |
| 361 | + | echo " • $line" | |
| 362 | + | done | |
| 363 | + | echo "" | |
| 364 | + | echo " Para empezar a usar tu laboratorio:" | |
| 365 | + | echo "" | |
| 366 | + | echo " 1. Abre la interfaz web (si tienes Docker):" | |
| 367 | + | echo " cd ${LAB_DIR}/docker" | |
| 368 | + | echo " docker compose up -d" | |
| 369 | + | echo " → http://localhost:3000" | |
| 370 | + | echo "" | |
| 371 | + | echo " 2. Chatea desde terminal:" | |
| 372 | + | echo " ollama run qwen2.5:3b \"¿Qué puedo hacer con IA local?\"" | |
| 373 | + | echo "" | |
| 374 | + | echo " 3. Prueba la API REST:" | |
| 375 | + | echo " curl http://localhost:11434/api/tags" | |
| 376 | + | echo "" | |
| 377 | + | echo " 4. Haz un respaldo:" | |
| 378 | + | echo " ${LAB_DIR}/scripts/backup.sh" | |
| 379 | + | echo "" | |
| 380 | + | echo " 📖 Guía completa en: atareao.es/827" | |
| 381 | + | echo "" | |
| 382 | + | echo " Próximo episodio (829): Skills imprescindibles para tu agente IA" | |
| 383 | + | echo " Vamos a enseñar al modelo a usar herramientas." | |
| 384 | + | echo "" | |
| 385 | + | echo " Nos oímos el jueves. Sed felices. Y seguid trasteando." | |
| 386 | + | echo "" | |
Próximo
Anterior