Files
VoiceStudio/install.sh
T

363 lines
13 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# OmniVoice Studio — universal installer.
#
# Works on macOS (ARM + Intel), Linux (Debian/Ubuntu, Fedora, Arch), and WSL.
# Run once, then `./run.sh` each time you want to use the app.
#
# Usage:
# curl -fsSL https://raw.githubusercontent.com/debpalash/OmniVoice-Studio/main/install.sh | sh
# # or locally:
# sh install.sh
# sh install.sh --verbose # show all subcommand output
# sh install.sh --python 3.12 # override Python version
set -e
# ── Output style ────────────────────────────────────────────────────────────
RULE=""
_rule_i=0
while [ "$_rule_i" -lt 56 ]; do
RULE="${RULE}─"
_rule_i=$((_rule_i + 1))
done
if [ -n "${NO_COLOR:-}" ]; then
C_TITLE="" C_DIM="" C_OK="" C_WARN="" C_ERR="" C_RST=""
elif [ -t 1 ] || [ -n "${FORCE_COLOR:-}" ]; then
_ESC="$(printf '\033')"
C_TITLE="${_ESC}[1;38;5;141m" # bold purple
C_DIM="${_ESC}[38;5;245m"
C_OK="${_ESC}[38;5;108m" # green
C_WARN="${_ESC}[38;5;136m" # yellow
C_ERR="${_ESC}[91m" # red
C_RST="${_ESC}[0m"
else
C_TITLE="" C_DIM="" C_OK="" C_WARN="" C_ERR="" C_RST=""
fi
step() { printf " ${C_DIM}%-18.18s${C_RST}${3:-$C_OK}%s${C_RST}\n" "$1" "$2"; }
note() { printf " ${C_DIM}%-18s${2:-$C_DIM}%s${C_RST}\n" "" "$1"; }
warn() { printf " ${C_WARN}⚠ %s${C_RST}\n" "$1"; }
die() { printf " ${C_ERR}✗ %s${C_RST}\n" "$1" >&2; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }
# ── Parse flags ─────────────────────────────────────────────────────────────
_VERBOSE=false
_USER_PYTHON=""
_next_is_python=false
for arg in "$@"; do
if [ "$_next_is_python" = true ]; then
_USER_PYTHON="$arg"
_next_is_python=false
continue
fi
case "$arg" in
--verbose|-v) _VERBOSE=true ;;
--python) _next_is_python=true ;;
esac
done
if [ "$_next_is_python" = true ]; then
die "--python requires a version argument (e.g. --python 3.12)"
fi
run_quiet() {
if [ "$_VERBOSE" = true ]; then
"$@"
else
"$@" > /dev/null 2>&1
fi
}
# ── Helper: download (curl or wget) ────────────────────────────────────────
download() {
if have curl; then
curl -LsSf "$1" -o "$2"
elif have wget; then
wget -qO "$2" "$1"
else
die "Neither curl nor wget found. Install one and re-run."
fi
}
# ── Helper: open browser (cross-platform) ──────────────────────────────────
open_browser() {
_url="$1"
if [ "$(uname)" = "Darwin" ] && have open; then
open "$_url"
elif grep -qi microsoft /proc/version 2>/dev/null; then
# WSL: use Windows browser
if have powershell.exe; then
powershell.exe -NoProfile -Command "Start-Process '$_url'" >/dev/null 2>&1 &
elif have cmd.exe; then
cmd.exe /c start "" "$_url" >/dev/null 2>&1 &
elif have xdg-open; then
xdg-open "$_url" >/dev/null 2>&1 &
else
echo " Open in your browser: $_url"
fi
elif have xdg-open; then
xdg-open "$_url" >/dev/null 2>&1 &
else
echo " Open in your browser: $_url"
fi
}
# ── Detect platform ────────────────────────────────────────────────────────
OS="linux"
if [ "$(uname)" = "Darwin" ]; then
OS="macos"
elif grep -qi microsoft /proc/version 2>/dev/null; then
OS="wsl"
fi
ARCH=$(uname -m)
echo ""
printf " ${C_TITLE}%s${C_RST}\n" "🎙 OmniVoice Studio Installer"
printf " ${C_DIM}%s${C_RST}\n" "$RULE"
echo ""
step "platform" "$OS ($ARCH)"
# Detect Rosetta on macOS
if [ "$OS" = "macos" ] && [ "$ARCH" = "x86_64" ]; then
if [ "$(sysctl -in hw.optional.arm64 2>/dev/null || echo 0)" = "1" ]; then
warn "Apple Silicon detected running under Rosetta (x86_64)."
note "Re-run from a native arm64 terminal for full MLX support."
fi
fi
# ── Resolve script directory (for local installs) ──────────────────────────
SCRIPT_DIR=""
if [ -n "${0:-}" ] && [ -f "$0" ]; then
SCRIPT_DIR=$(cd "$(dirname "$0")" 2>/dev/null && pwd) || true
fi
if [ -z "$SCRIPT_DIR" ]; then
SCRIPT_DIR=$(pwd)
fi
# If run via curl pipe, clone the repo first
if [ ! -f "$SCRIPT_DIR/pyproject.toml" ]; then
step "clone" "downloading OmniVoice Studio..."
INSTALL_DIR="$HOME/OmniVoice"
if [ -d "$INSTALL_DIR/.git" ]; then
note "Updating existing clone at $INSTALL_DIR"
(cd "$INSTALL_DIR" && git pull --ff-only 2>/dev/null || true)
else
if have git; then
git clone --depth 1 https://github.com/debpalash/OmniVoice-Studio.git "$INSTALL_DIR"
else
die "git is required. Install git and re-run."
fi
fi
SCRIPT_DIR="$INSTALL_DIR"
fi
cd "$SCRIPT_DIR"
# ── Python version ──────────────────────────────────────────────────────────
if [ -n "$_USER_PYTHON" ]; then
PYTHON_VERSION="$_USER_PYTHON"
note "Using user-specified Python $PYTHON_VERSION"
else
PYTHON_VERSION="3.11"
fi
# ── System dependencies ────────────────────────────────────────────────────
# Helper: install system packages with the right package manager
_install_sys_pkgs() {
case "$OS" in
macos)
if ! have brew; then
note "Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" </dev/null
if [ -x /opt/homebrew/bin/brew ]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ -x /usr/local/bin/brew ]; then
eval "$(/usr/local/bin/brew shellenv)"
fi
fi
brew install "$@" </dev/null 2>/dev/null || true
;;
linux|wsl)
if have apt-get; then
# Try without sudo first, then escalate
apt-get update -y </dev/null >/dev/null 2>&1 || true
apt-get install -y "$@" </dev/null >/dev/null 2>&1 || {
if have sudo; then
echo ""
echo " Need elevated permissions to install: $*"
sudo apt-get update -y </dev/null
sudo apt-get install -y "$@" </dev/null
else
die "Cannot install $*. Run as root or install manually."
fi
}
elif have dnf; then
sudo dnf install -y "$@" </dev/null 2>/dev/null || true
elif have yum; then
sudo yum install -y "$@" </dev/null 2>/dev/null || true
elif have pacman; then
sudo pacman -S --noconfirm "$@" 2>/dev/null || true
else
warn "No supported package manager found. Please install manually: $*"
fi
;;
esac
}
# Xcode CLT (macOS only)
if [ "$OS" = "macos" ]; then
step "xcode" "checking..."
if ! xcode-select -p >/dev/null 2>&1; then
note "Installing Xcode Command Line Tools..."
xcode-select --install </dev/null 2>/dev/null || true
until xcode-select -p >/dev/null 2>&1; do
note "Waiting for Xcode CLT install..."
sleep 10
done
fi
step "xcode" "$(xcode-select -p)"
fi
# ffmpeg (required for audio/video processing)
step "ffmpeg" "checking..."
if ! have ffmpeg; then
note "Installing ffmpeg..."
case "$OS" in
macos) _install_sys_pkgs ffmpeg ;;
linux|wsl)
if have apt-get; then
_install_sys_pkgs ffmpeg
elif have dnf; then
_install_sys_pkgs ffmpeg-free # Fedora
elif have pacman; then
_install_sys_pkgs ffmpeg
else
warn "Please install ffmpeg manually."
fi
;;
esac
fi
if have ffmpeg; then
step "ffmpeg" "$(ffmpeg -version 2>/dev/null | head -n1 | cut -d' ' -f1-3)"
else
warn "ffmpeg not found — some features will be unavailable."
fi
# ── Install uv ──────────────────────────────────────────────────────────────
step "uv" "checking..."
UV_MIN_VERSION="0.7.0"
_version_ge() {
# Returns 0 if $1 >= $2 (dotted version comparison)
_a=$1; _b=$2
while [ -n "$_a" ] || [ -n "$_b" ]; do
_a_part=${_a%%.*}; _b_part=${_b%%.*}
[ "$_a" = "$_a_part" ] && _a="" || _a=${_a#*.}
[ "$_b" = "$_b_part" ] && _b="" || _b=${_b#*.}
[ -z "$_a_part" ] && _a_part=0
[ -z "$_b_part" ] && _b_part=0
if [ "$_a_part" -gt "$_b_part" ] 2>/dev/null; then return 0; fi
if [ "$_a_part" -lt "$_b_part" ] 2>/dev/null; then return 1; fi
done
return 0
}
_uv_ok() {
have uv || return 1
_raw=$(uv --version 2>/dev/null | awk '{print $2}') || return 1
[ -n "$_raw" ] || return 1
_ver=${_raw%%[-+]*}
_version_ge "$_ver" "$UV_MIN_VERSION"
}
if ! _uv_ok; then
note "Installing uv package manager..."
_uv_tmp=$(mktemp)
download "https://astral.sh/uv/install.sh" "$_uv_tmp"
run_quiet sh "$_uv_tmp" </dev/null
rm -f "$_uv_tmp"
# Source env if uv's installer created it
if [ -f "$HOME/.local/bin/env" ]; then
. "$HOME/.local/bin/env"
fi
export PATH="$HOME/.local/bin:$PATH"
fi
step "uv" "$(uv --version 2>/dev/null)"
# ── Install bun (JS runtime for frontend) ──────────────────────────────────
step "bun" "checking..."
if ! have bun; then
note "Installing bun..."
if have curl; then
curl -fsSL https://bun.sh/install | sh </dev/null
else
die "curl is required to install bun."
fi
export PATH="$HOME/.bun/bin:$PATH"
fi
step "bun" "bun $(bun --version 2>/dev/null)"
# ── GPU detection (informational) ──────────────────────────────────────────
step "gpu" "detecting..."
GPU_INFO="CPU only"
if [ "$OS" = "macos" ] && [ "$ARCH" = "arm64" ]; then
GPU_INFO="Apple Silicon (Metal/MPS)"
elif have nvidia-smi; then
_gpu_name=$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null | head -1)
_cuda_ver=$(nvidia-smi 2>/dev/null | sed -n 's/.*CUDA Version:[[:space:]]*\([0-9]*\.[0-9]*\).*/\1/p' | head -1)
if [ -n "$_gpu_name" ]; then
GPU_INFO="NVIDIA $_gpu_name (CUDA $_cuda_ver)"
fi
elif have rocminfo; then
_amd_name=$(rocminfo 2>/dev/null | awk '/Marketing Name:/{$1=$2=""; print; exit}' | sed 's/^ *//')
if [ -n "$_amd_name" ]; then
GPU_INFO="AMD $_amd_name (ROCm)"
fi
fi
step "gpu" "$GPU_INFO"
# ── Python dependencies via uv ──────────────────────────────────────────────
step "python" "syncing dependencies..."
note "This can take 510 min the first time (torch + torchaudio + demucs...)"
# Create venv with the target Python version if it doesn't exist
if [ ! -d .venv ]; then
uv venv --python "$PYTHON_VERSION"
fi
# Sync all deps from pyproject.toml + uv.lock
uv sync
step "python" "OK — virtualenv at .venv/"
# ── Frontend deps + build ──────────────────────────────────────────────────
step "frontend" "installing dependencies..."
(cd frontend && bun install)
step "frontend" "OK"
step "frontend" "building bundle..."
(cd frontend && bun run build)
step "frontend" "OK — output at frontend/dist/"
# ── Log directory ──────────────────────────────────────────────────────────
case "$OS" in
macos) LOG_DIR="$HOME/Library/Application Support/OmniVoice" ;;
*) LOG_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/OmniVoice" ;;
esac
mkdir -p "$LOG_DIR"
# ── Done ────────────────────────────────────────────────────────────────────
echo ""
printf " ${C_TITLE}%s${C_RST}\n" "✓ Install complete!"
printf " ${C_DIM}%s${C_RST}\n" "$RULE"
echo ""
step "next" "Run ./run.sh to start OmniVoice Studio"
echo ""
note "First launch downloads ~5 GB of ML model weights (OmniVoice TTS + Whisper)."
note "After that, launches are instant."
echo ""
note "GPU: $GPU_INFO"
note "Logs: $LOG_DIR/omnivoice.log"
echo ""