#!/usr/bin/env bash # ───────────────────────────────────────────────────────────── # LLM Trainer — .deb package builder # Run this on the Ubuntu machine after cloning the repo: # chmod +x packaging/build-deb.sh # ./packaging/build-deb.sh # ───────────────────────────────────────────────────────────── set -euo pipefail PKG_NAME="llm-trainer" PKG_VERSION="1.0.0" PKG_ARCH="amd64" PKG_DIR="${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" OUT_DIR="${REPO_ROOT}" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " LLM Trainer .deb Builder" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" # ── Check dependencies ──────────────────────────────────────── for cmd in node npm python3 pip3 dpkg-deb nginx; do if ! command -v "$cmd" &>/dev/null; then echo "[ERROR] Required command not found: $cmd" echo " Install with: sudo apt install nodejs npm python3-pip nginx" exit 1 fi done # ── Build frontend ──────────────────────────────────────────── echo "" echo "[1/4] Building React frontend..." cd "${REPO_ROOT}/frontend" npm install --silent npm run build echo " Frontend built → frontend/dist" # ── Create package directory tree ───────────────────────────── echo "" echo "[2/4] Creating package structure..." BUILD="${REPO_ROOT}/${PKG_DIR}" rm -rf "${BUILD}" install -d "${BUILD}/DEBIAN" install -d "${BUILD}/opt/llm-trainer/backend" install -d "${BUILD}/opt/llm-trainer/frontend" install -d "${BUILD}/opt/llm-trainer/venv" install -d "${BUILD}/lib/systemd/system" install -d "${BUILD}/etc/nginx/sites-available" install -d "${BUILD}/etc/nginx/sites-enabled" install -d "${BUILD}/etc/llm-trainer" install -d "${BUILD}/var/log/llm-trainer" # Copy backend cp "${REPO_ROOT}/backend/"*.py "${BUILD}/opt/llm-trainer/backend/" cp "${REPO_ROOT}/backend/requirements.txt" "${BUILD}/opt/llm-trainer/backend/" # Copy built frontend cp -r "${REPO_ROOT}/frontend/dist/." "${BUILD}/opt/llm-trainer/frontend/" # ── Write control files ─────────────────────────────────────── cat > "${BUILD}/DEBIAN/control" <= 3.10), python3-pip, python3-venv, nginx Description: LLM Trainer Dashboard Web dashboard for managing LLM training pipelines via SSH. Includes document ingestion, QA pair generation, curation, training monitor, and an interactive terminal. EOF # ── Systemd service ─────────────────────────────────────────── cat > "${BUILD}/lib/systemd/system/llm-trainer.service" < "${BUILD}/etc/nginx/sites-available/llm-trainer" <<'EOF' server { listen 3000; server_name _; root /opt/llm-trainer/frontend; index index.html; # Serve React SPA location / { try_files $uri $uri/ /index.html; } # Proxy REST API to FastAPI backend location /api/ { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # WebSocket support (terminal, log streaming) proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400; } } EOF # ── postinst ────────────────────────────────────────────────── cat > "${BUILD}/DEBIAN/postinst" <<'POSTINST' #!/bin/bash set -e # Create system user if ! id -u llm-trainer &>/dev/null; then useradd --system --no-create-home --shell /usr/sbin/nologin llm-trainer fi # Set permissions chown -R llm-trainer:llm-trainer /opt/llm-trainer chown -R llm-trainer:llm-trainer /var/log/llm-trainer # Write default env config (only on first install) if [ ! -f /etc/llm-trainer/env ]; then cat > /etc/llm-trainer/env <<'ENV' # LLM Trainer configuration # Override Ollama URL if it runs on a different host OLLAMA_URL=http://localhost:11434 ENV fi # Build Python venv and install deps echo "Installing Python dependencies..." python3 -m venv /opt/llm-trainer/venv /opt/llm-trainer/venv/bin/pip install --quiet --upgrade pip /opt/llm-trainer/venv/bin/pip install --quiet -r /opt/llm-trainer/backend/requirements.txt chown -R llm-trainer:llm-trainer /opt/llm-trainer/venv # Enable nginx site ln -sf /etc/nginx/sites-available/llm-trainer /etc/nginx/sites-enabled/llm-trainer nginx -t && systemctl reload nginx || true # Enable and start backend service systemctl daemon-reload systemctl enable llm-trainer systemctl start llm-trainer echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " LLM Trainer installed successfully!" echo " Open: http://$(hostname -I | awk '{print $1}'):3000" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" POSTINST chmod 0755 "${BUILD}/DEBIAN/postinst" # ── prerm ───────────────────────────────────────────────────── cat > "${BUILD}/DEBIAN/prerm" <<'PRERM' #!/bin/bash set -e systemctl stop llm-trainer 2>/dev/null || true systemctl disable llm-trainer 2>/dev/null || true rm -f /etc/nginx/sites-enabled/llm-trainer systemctl reload nginx 2>/dev/null || true PRERM chmod 0755 "${BUILD}/DEBIAN/prerm" # ── postrm ──────────────────────────────────────────────────── cat > "${BUILD}/DEBIAN/postrm" <<'POSTRM' #!/bin/bash set -e if [ "$1" = "purge" ]; then rm -rf /opt/llm-trainer rm -rf /var/log/llm-trainer rm -f /etc/nginx/sites-available/llm-trainer userdel llm-trainer 2>/dev/null || true fi POSTRM chmod 0755 "${BUILD}/DEBIAN/postrm" # ── Build .deb ──────────────────────────────────────────────── echo "" echo "[3/4] Building .deb package..." cd "${REPO_ROOT}" dpkg-deb --build --root-owner-group "${PKG_DIR}" echo " Package built → ${PKG_DIR}.deb" # ── Cleanup ─────────────────────────────────────────────────── rm -rf "${BUILD}" echo "" echo "[4/4] Done!" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Install with:" echo " sudo dpkg -i ${PKG_DIR}.deb" echo " sudo apt-get install -f # fix any missing deps" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"