coconews/deploy/debian/prerequisites.sh
SITO e3c682a36f feat: prerequisites, POC local y README reescrito
deploy/debian/prerequisites.sh:
- Instalador de dependencias del sistema para Debian/Ubuntu
- Detecta OS, instala PostgreSQL 16 (repo oficial), Redis, nginx,
  Go 1.25, Node.js 20 LTS, Qdrant binario, Python venv
- Crea usuario rss2 y estructura /opt/rss2
- Pregunta interactivamente si instalar modelos ML pesados
  (ctranslate2, transformers, spaCy es_core_news_lg, NLLB-200)
- Separado de install.sh para poder ejecutarlo independientemente

poc/poc.sh:
- POC local en ~2 minutos sin Docker, sin workers ML
- Crea BD temporal coconews_poc con schema completo
- Carga 10 noticias de muestra en español listas para ver
- Compila backend Go y frontend React en /tmp/coconews-poc
- Lanza Redis en puerto alternativo (6380) sin interferir
- Sirve frontend con npx serve en http://127.0.0.1:18001
- Limpieza automatica al Ctrl+C

poc/seed.sql:
- 10 noticias de muestra en español (no requieren traduccion)
- Categorias, continentes y paises basicos
- 5 feeds de ejemplo (El Pais, BBC Mundo, etc.)

README.md:
- Reescrito completamente sin referencias Docker
- Diagrama ASCII de arquitectura
- Inicio rapido con poc.sh (2 minutos)
- Instrucciones de install en Debian con prerequisites.sh
- Tabla de requisitos hardware por modo
- Mapa completo del repositorio

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 21:17:11 +02:00

305 lines
11 KiB
Bash
Executable file

#!/usr/bin/env bash
# =============================================================================
# COCONEWS - Instalacion de prerequisites en Debian 12 / Ubuntu 22.04+
# Ejecutar ANTES de install.sh
# Uso: sudo bash prerequisites.sh
# =============================================================================
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
info() { echo -e "${GREEN}[OK]${NC} $*"; }
step() { echo -e "${BLUE}[-->]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }
[[ "$EUID" -ne 0 ]] && error "Ejecutar como root: sudo bash prerequisites.sh"
# Detectar OS
if [[ -f /etc/os-release ]]; then
. /etc/os-release
OS_ID="$ID"
OS_VER="$VERSION_ID"
else
error "No se puede detectar el sistema operativo"
fi
[[ "$OS_ID" == "debian" || "$OS_ID" == "ubuntu" ]] || \
error "Solo soportado en Debian/Ubuntu. Detectado: $OS_ID"
echo ""
echo "================================================="
echo " COCONEWS - Instalador de Prerequisites"
echo " OS: $PRETTY_NAME"
echo "================================================="
echo ""
# =============================================================================
# 1. PAQUETES APT BASE
# =============================================================================
step "Actualizando repositorios apt..."
apt-get update -qq
step "Instalando paquetes del sistema..."
apt-get install -y --no-install-recommends \
curl wget git build-essential \
ca-certificates gnupg lsb-release \
software-properties-common apt-transport-https \
tzdata locales \
rsync \
openssl \
libpq-dev \
libssl-dev \
libffi-dev \
libbz2-dev \
libreadline-dev \
libsqlite3-dev \
zlib1g-dev
info "Paquetes base instalados"
# =============================================================================
# 2. POSTGRESQL 16
# =============================================================================
step "Instalando PostgreSQL 16..."
if ! command -v psql &>/dev/null; then
# Repositorio oficial de PostgreSQL
install -d /usr/share/postgresql-common/pgdg
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
| gpg --dearmor -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg
echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.gpg] \
https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
> /etc/apt/sources.list.d/pgdg.list
apt-get update -qq
apt-get install -y postgresql-16 postgresql-client-16
fi
info "PostgreSQL: $(psql --version)"
# =============================================================================
# 3. REDIS
# =============================================================================
step "Instalando Redis..."
if ! command -v redis-server &>/dev/null; then
apt-get install -y redis-server
fi
info "Redis: $(redis-server --version | cut -d' ' -f3)"
# =============================================================================
# 4. NGINX
# =============================================================================
step "Instalando Nginx..."
if ! command -v nginx &>/dev/null; then
apt-get install -y nginx
fi
info "Nginx: $(nginx -v 2>&1 | cut -d'/' -f2)"
# =============================================================================
# 5. PYTHON 3 + pip + venv
# =============================================================================
step "Instalando Python 3..."
apt-get install -y python3 python3-pip python3-venv python3-dev
info "Python: $(python3 --version)"
# =============================================================================
# 6. NODE.JS 20 LTS
# =============================================================================
step "Instalando Node.js 20 LTS..."
if ! command -v node &>/dev/null || [[ "$(node -v | tr -d 'v' | cut -d. -f1)" -lt 18 ]]; then
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs
fi
info "Node.js: $(node --version) | npm: $(npm --version)"
# =============================================================================
# 7. GO 1.25
# =============================================================================
step "Instalando Go 1.25..."
GO_VERSION="1.25.0"
INSTALLED_GO=$(go version 2>/dev/null | awk '{print $3}' | tr -d 'go' || echo "0")
# Comparar version instalada
needs_go=false
if ! command -v go &>/dev/null; then
needs_go=true
else
IFS='.' read -ra INS <<< "$INSTALLED_GO"
IFS='.' read -ra REQ <<< "$GO_VERSION"
if [[ "${INS[0]}" -lt "${REQ[0]}" ]] || \
([[ "${INS[0]}" == "${REQ[0]}" ]] && [[ "${INS[1]:-0}" -lt "${REQ[1]:-0}" ]]); then
needs_go=true
fi
fi
if [[ "$needs_go" == "true" ]]; then
ARCH=$(dpkg --print-architecture)
case "$ARCH" in
amd64) GO_ARCH="amd64" ;;
arm64) GO_ARCH="arm64" ;;
*) error "Arquitectura no soportada para Go: $ARCH" ;;
esac
step " Descargando Go ${GO_VERSION} (${GO_ARCH})..."
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz" -o /tmp/go.tar.gz
rm -rf /usr/local/go
tar -C /usr/local -xzf /tmp/go.tar.gz
rm /tmp/go.tar.gz
# Perfil global
cat > /etc/profile.d/golang.sh << 'GOEOF'
export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
GOEOF
chmod +x /etc/profile.d/golang.sh
export PATH=$PATH:/usr/local/go/bin
info "Go instalado: $(go version)"
else
export PATH=$PATH:/usr/local/go/bin
info "Go ya instalado: $(go version)"
fi
# =============================================================================
# 8. QDRANT (binario oficial)
# =============================================================================
step "Instalando Qdrant..."
QDRANT_VERSION="v1.12.1"
QDRANT_INSTALL_DIR="/opt/rss2/qdrant"
mkdir -p "$QDRANT_INSTALL_DIR"
if [[ ! -f "$QDRANT_INSTALL_DIR/qdrant" ]]; then
ARCH=$(dpkg --print-architecture)
case "$ARCH" in
amd64) QDRANT_ARCH="x86_64-unknown-linux-musl" ;;
arm64) QDRANT_ARCH="aarch64-unknown-linux-musl" ;;
*) error "Arquitectura no soportada para Qdrant: $ARCH" ;;
esac
step " Descargando Qdrant ${QDRANT_VERSION}..."
curl -fsSL \
"https://github.com/qdrant/qdrant/releases/download/${QDRANT_VERSION}/qdrant-${QDRANT_ARCH}.tar.gz" \
-o /tmp/qdrant.tar.gz
tar -C "$QDRANT_INSTALL_DIR" -xzf /tmp/qdrant.tar.gz
chmod +x "$QDRANT_INSTALL_DIR/qdrant"
rm /tmp/qdrant.tar.gz
info "Qdrant ${QDRANT_VERSION} instalado en ${QDRANT_INSTALL_DIR}"
else
info "Qdrant ya instalado en ${QDRANT_INSTALL_DIR}"
fi
# =============================================================================
# 9. USUARIO DEL SISTEMA rss2
# =============================================================================
step "Creando usuario del sistema 'rss2'..."
if ! id rss2 &>/dev/null; then
useradd -r -m -d /opt/rss2 -s /bin/bash rss2
info "Usuario 'rss2' creado"
else
info "Usuario 'rss2' ya existe"
fi
# Crear estructura de directorios
mkdir -p \
/opt/rss2/bin \
/opt/rss2/src \
/opt/rss2/data/wiki_images \
/opt/rss2/data/qdrant_storage \
/opt/rss2/hf_cache \
/opt/rss2/models \
/opt/rss2/frontend/dist \
/opt/rss2/logs \
/opt/rss2/backups
chown -R rss2:rss2 /opt/rss2
info "Directorios /opt/rss2 creados"
# =============================================================================
# 10. PYTHON VIRTUALENV + DEPENDENCIAS BASE
# =============================================================================
step "Creando virtualenv Python en /opt/rss2/venv..."
if [[ ! -d /opt/rss2/venv ]]; then
python3 -m venv /opt/rss2/venv
fi
/opt/rss2/venv/bin/pip install --upgrade pip setuptools wheel -q
info "Virtualenv listo"
# Dependencias base (sin los modelos pesados de ML)
step "Instalando dependencias Python base..."
/opt/rss2/venv/bin/pip install -q \
psycopg2-binary \
langdetect \
python-dotenv \
requests \
beautifulsoup4 \
lxml \
redis \
qdrant-client \
numpy \
scikit-learn \
tqdm
info "Dependencias Python base instaladas"
# =============================================================================
# 11. DEPENDENCIAS ML (pesadas - opcional en este paso)
# =============================================================================
echo ""
echo -e "${YELLOW}[?]${NC} Instalar dependencias ML pesadas ahora?"
echo " (ctranslate2, transformers, sentence-transformers, spaCy)"
echo " Puede tardar 20-40 minutos y usar ~5 GB de disco."
echo -n " [s/N]: "
read -r install_ml
if [[ "${install_ml,,}" == "s" || "${install_ml,,}" == "si" || "${install_ml,,}" == "y" ]]; then
step "Instalando dependencias ML (esto tarda)..."
/opt/rss2/venv/bin/pip install -q \
ctranslate2>=4.0.0 \
transformers==4.43.3 \
sentencepiece \
sacremoses \
accelerate \
sentence-transformers==3.0.1 \
"spacy>=3.7,<4.0" \
torch --index-url https://download.pytorch.org/whl/cpu
info "Dependencias ML instaladas"
step "Descargando modelo spaCy en español..."
/opt/rss2/venv/bin/python -m spacy download es_core_news_lg
info "Modelo spaCy es_core_news_lg listo"
step "Convirtiendo modelo NLLB-200 a CTranslate2..."
warn "Esto puede tardar 10-30 minutos y requiere ~2 GB de RAM"
mkdir -p /opt/rss2/models
/opt/rss2/venv/bin/python - <<'EOF'
import os, sys
os.makedirs("/opt/rss2/models/nllb-ct2", exist_ok=True)
os.environ["HF_HOME"] = "/opt/rss2/hf_cache"
try:
from ctranslate2.converters import OpusMTConverter
converter = OpusMTConverter("facebook/nllb-200-distilled-600M")
converter.convert("/opt/rss2/models/nllb-ct2", quantization="int8", force=True)
print("[OK] Modelo NLLB-200 convertido en /opt/rss2/models/nllb-ct2")
except Exception as e:
print(f"[ERROR] {e}")
print("Convierte manualmente despues con: deploy/debian/convert_model.sh")
sys.exit(0)
EOF
chown -R rss2:rss2 /opt/rss2/models /opt/rss2/hf_cache
else
warn "ML omitido. Ejecuta 'deploy/debian/install.sh' para instalarlas junto con el resto."
warn "Sin ML: la traduccion y los embeddings no funcionaran."
fi
chown -R rss2:rss2 /opt/rss2
# =============================================================================
# RESUMEN
# =============================================================================
echo ""
echo "================================================="
echo -e " ${GREEN}Prerequisites instalados correctamente${NC}"
echo "================================================="
echo ""
echo " Sistema: $PRETTY_NAME"
echo " Go: $(go version 2>/dev/null | awk '{print $3}')"
echo " Python: $(python3 --version)"
echo " Node.js: $(node --version)"
echo " PostgreSQL: $(psql --version | awk '{print $3}')"
echo " Redis: $(redis-server --version | awk '{print $3}' | tr -d ',')"
echo " Nginx: $(nginx -v 2>&1 | cut -d'/' -f2)"
echo ""
echo " Siguiente paso:"
echo " sudo bash deploy/debian/install.sh"
echo ""