Files
dictia-public/deployment/setup.sh

301 lines
10 KiB
Bash
Executable File

#!/usr/bin/env bash
# DictIA — Main setup script
#
# Interactive installer that detects hardware and configures the appropriate
# deployment profile (cloud, local-cpu, local-gpu).
#
# Usage:
# bash deployment/setup.sh # Interactive mode
# bash deployment/setup.sh --profile cloud # Non-interactive
# bash deployment/setup.sh --profile local-gpu
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
PROFILE=""
for arg in "$@"; do
case "$arg" in
--profile=*) PROFILE="${arg#*=}" ;;
--profile) shift_next=true ;;
*)
if [ "${shift_next:-false}" = true ]; then
PROFILE="$arg"
shift_next=false
fi
;;
esac
done
# --- Colors ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
err() { echo -e "${RED}[ERROR]${NC} $*"; }
echo
echo -e "${CYAN}========================================${NC}"
echo -e "${CYAN} DictIA — Setup${NC}"
echo -e "${CYAN}========================================${NC}"
echo
# ==========================================================================
# 1. Hardware Detection
# ==========================================================================
info "Detecting hardware..."
# Docker
if command -v docker &>/dev/null && docker info &>/dev/null; then
DOCKER_VERSION=$(docker --version | grep -oP '\d+\.\d+\.\d+' | head -1)
ok "Docker $DOCKER_VERSION"
else
err "Docker not found or not running."
echo " Install Docker: https://docs.docker.com/engine/install/"
exit 1
fi
# Docker Compose
if docker compose version &>/dev/null; then
COMPOSE_VERSION=$(docker compose version --short 2>/dev/null || echo "unknown")
ok "Docker Compose $COMPOSE_VERSION"
else
err "Docker Compose not found."
echo " Docker Compose V2 is required (comes with Docker Desktop or docker-compose-plugin)"
exit 1
fi
# GPU
HAS_GPU=false
if command -v nvidia-smi &>/dev/null; then
GPU_NAME=$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null | head -1 || echo "")
if [ -n "$GPU_NAME" ]; then
HAS_GPU=true
ok "NVIDIA GPU: $GPU_NAME"
# Check nvidia-container-toolkit
if docker info 2>/dev/null | grep -qi nvidia; then
ok "nvidia-container-toolkit detected"
else
warn "nvidia-container-toolkit not detected. Required for local-gpu profile."
echo " Install: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html"
fi
fi
else
info "No NVIDIA GPU detected"
fi
# RAM
if command -v free &>/dev/null; then
RAM_GB=$(free -g | awk '/Mem:/{print $2}')
info "RAM: ${RAM_GB}GB"
fi
# Disk
DISK_AVAIL=$(df -h "$PROJECT_DIR" 2>/dev/null | awk 'NR==2{print $4}')
info "Disk available: $DISK_AVAIL"
echo
# ==========================================================================
# 2. Profile Selection
# ==========================================================================
if [ -z "$PROFILE" ]; then
echo -e "${CYAN}Select deployment profile:${NC}"
echo
echo " 1) cloud — VPS with ASR Proxy (GCP GPU on demand)"
echo " Best for: remote servers, pay-per-use GPU"
echo
echo " 2) local-gpu — Local NVIDIA GPU for transcription"
echo " Best for: dedicated GPU server, fastest"
if [ "$HAS_GPU" = false ]; then
echo -e " ${YELLOW}(No GPU detected on this machine)${NC}"
fi
echo
echo " 3) local-cpu — CPU-only transcription (slow)"
echo " Best for: testing, low-volume usage"
echo
read -rp "Choice [1-3]: " CHOICE
case "$CHOICE" in
1) PROFILE="cloud" ;;
2) PROFILE="local-gpu" ;;
3) PROFILE="local-cpu" ;;
*) err "Invalid choice"; exit 1 ;;
esac
fi
COMPOSE_FILE="$SCRIPT_DIR/docker/docker-compose.$PROFILE.yml"
if [ ! -f "$COMPOSE_FILE" ]; then
err "Compose file not found: $COMPOSE_FILE"
exit 1
fi
ok "Profile: $PROFILE"
echo
# ==========================================================================
# 3. Generate .env
# ==========================================================================
ENV_FILE="$PROJECT_DIR/.env"
if [ -f "$ENV_FILE" ]; then
warn ".env already exists. Keeping existing configuration."
echo " To reconfigure, delete .env and re-run setup."
else
info "Generating .env..."
# Generate secret key
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))" 2>/dev/null \
|| openssl rand -hex 32 2>/dev/null \
|| head -c 64 /dev/urandom | xxd -p | head -c 64)
# Prompt for admin credentials
read -rp "Admin username [admin]: " ADMIN_USER
ADMIN_USER="${ADMIN_USER:-admin}"
read -rp "Admin email [admin@example.com]: " ADMIN_EMAIL
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@example.com}"
read -rsp "Admin password: " ADMIN_PASS
echo
ADMIN_PASS="${ADMIN_PASS:-changeme}"
# Prompt for text model API key
echo
info "DictIA needs a text/LLM API key for summaries, titles, and chat."
echo " Recommended: OpenRouter (https://openrouter.ai) — access to many models"
read -rp "Text model API key (or press Enter to skip): " TEXT_API_KEY
TEXT_API_KEY="${TEXT_API_KEY:-your_openrouter_api_key}"
# HuggingFace token for diarization
if [ "$PROFILE" != "cloud" ]; then
echo
info "For speaker diarization, a HuggingFace token is needed."
echo " Get one at: https://huggingface.co/settings/tokens"
echo " Accept model: https://huggingface.co/pyannote/speaker-diarization-3.1"
read -rp "HuggingFace token (or press Enter to skip): " HF_TOKEN
HF_TOKEN="${HF_TOKEN:-}"
else
HF_TOKEN=""
fi
# Write .env
cp "$SCRIPT_DIR/docker/.env.example" "$ENV_FILE"
sed -i "s|SECRET_KEY=.*|SECRET_KEY=$SECRET_KEY|" "$ENV_FILE"
sed -i "s|DICTIA_PROFILE=.*|DICTIA_PROFILE=$PROFILE|" "$ENV_FILE"
sed -i "s|ADMIN_USERNAME=.*|ADMIN_USERNAME=$ADMIN_USER|" "$ENV_FILE"
sed -i "s|ADMIN_EMAIL=.*|ADMIN_EMAIL=$ADMIN_EMAIL|" "$ENV_FILE"
sed -i "s|ADMIN_PASSWORD=.*|ADMIN_PASSWORD=$ADMIN_PASS|" "$ENV_FILE"
sed -i "s|TEXT_MODEL_API_KEY=.*|TEXT_MODEL_API_KEY=$TEXT_API_KEY|" "$ENV_FILE"
sed -i "s|HF_TOKEN=.*|HF_TOKEN=$HF_TOKEN|" "$ENV_FILE"
ok ".env generated"
fi
echo
# ==========================================================================
# 4. Create data directories
# ==========================================================================
info "Creating data directories..."
mkdir -p "$PROJECT_DIR/data/uploads" "$PROJECT_DIR/data/instance"
ok "data/uploads and data/instance created"
echo
# ==========================================================================
# 5. Profile-specific setup
# ==========================================================================
case "$PROFILE" in
cloud)
info "Cloud profile — setting up ASR Proxy..."
if [ -f "$SCRIPT_DIR/asr-proxy/setup.sh" ]; then
echo " Run the ASR proxy setup separately:"
echo " bash $SCRIPT_DIR/asr-proxy/setup.sh"
fi
echo
info "Setting up iptables rules..."
if [ -f "$SCRIPT_DIR/security/iptables-rules.sh" ] && [ "$(id -u)" -eq 0 ]; then
bash "$SCRIPT_DIR/security/iptables-rules.sh"
else
echo " Run as root: sudo bash $SCRIPT_DIR/security/iptables-rules.sh"
fi
echo
info "Setting up Tailscale Serve..."
if command -v tailscale &>/dev/null; then
echo " Run: bash $SCRIPT_DIR/config/tailscale/setup-serve.sh"
else
warn "Tailscale not installed."
echo " Install: curl -fsSL https://tailscale.com/install.sh | sh"
fi
;;
local-gpu)
info "Local GPU profile — verifying NVIDIA runtime..."
if docker info 2>/dev/null | grep -qi nvidia; then
ok "NVIDIA Docker runtime available"
# Quick GPU test
if docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi &>/dev/null; then
ok "GPU test passed"
else
warn "GPU test failed. Check nvidia-container-toolkit installation."
fi
else
err "NVIDIA Docker runtime not found."
echo " Install nvidia-container-toolkit and restart Docker."
echo " https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html"
fi
;;
local-cpu)
warn "CPU-only transcription is significantly slower than GPU."
echo " Expect ~10x real-time (1h audio = ~10h processing)."
echo " Consider local-gpu or cloud profile for better performance."
;;
esac
echo
# ==========================================================================
# 6. Build and start
# ==========================================================================
info "Building DictIA Docker image..."
cd "$PROJECT_DIR"
docker build -t innova-ai/dictia:latest .
ok "Image built"
echo
info "Starting DictIA ($PROFILE profile)..."
docker compose -f "$COMPOSE_FILE" up -d
ok "Containers started"
# ==========================================================================
# 7. Health check
# ==========================================================================
echo
info "Waiting for DictIA to become healthy..."
RETRIES=30
for i in $(seq 1 $RETRIES); do
if curl -sf -o /dev/null -m 5 http://localhost:8899/health 2>/dev/null; then
ok "DictIA is healthy!"
break
fi
if [ "$i" -eq "$RETRIES" ]; then
warn "Health check timeout. Check logs: docker compose -f $COMPOSE_FILE logs"
fi
sleep 5
done
echo
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN} DictIA is ready!${NC}"
echo -e "${GREEN}========================================${NC}"
echo
echo " App: http://localhost:8899"
echo " Profile: $PROFILE"
echo " Compose: $COMPOSE_FILE"
echo
echo " Tools:"
echo " Update: bash deployment/tools/update.sh"
echo " Backup: bash deployment/tools/backup.sh"
echo " Health check: bash deployment/tools/health-check.sh"
echo