#!/bin/sh # Unsloth Studio Installer # Usage (curl): curl -fsSL https://raw.githubusercontent.com/unslothai/unsloth/main/install.sh | sh # Usage (wget): wget -qO- https://raw.githubusercontent.com/unslothai/unsloth/main/install.sh | sh set -e VENV_NAME="unsloth_studio" PYTHON_VERSION="3.13" # ── Helper: download a URL to a file (supports curl and wget) ── download() { if command -v curl >/dev/null 2>&1; then curl -LsSf "$1" -o "$2" elif command -v wget >/dev/null 2>&1; then wget -qO "$2" "$1" else echo "Error: neither curl nor wget found. Install one and re-run." exit 1 fi } # ── Helper: check if a single package is available on the system ── _is_pkg_installed() { case "$1" in build-essential) command -v gcc >/dev/null 2>&1 ;; libcurl4-openssl-dev) command -v dpkg >/dev/null 2>&1 && dpkg -s "$1" >/dev/null 2>&1 ;; pciutils) command -v lspci >/dev/null 2>&1 ;; *) command -v "$1" >/dev/null 2>&1 ;; esac } # ── Helper: install packages via apt, escalating to sudo only if needed ── # Usage: _smart_apt_install pkg1 pkg2 pkg3 ... _smart_apt_install() { _PKGS="$*" # Step 1: Try installing without sudo (works when already root) apt-get update -y /dev/null 2>&1 || true apt-get install -y $_PKGS /dev/null 2>&1 || true # Step 2: Check which packages are still missing _STILL_MISSING="" for _pkg in $_PKGS; do if ! _is_pkg_installed "$_pkg"; then _STILL_MISSING="$_STILL_MISSING $_pkg" fi done _STILL_MISSING=$(echo "$_STILL_MISSING" | sed 's/^ *//') if [ -z "$_STILL_MISSING" ]; then return 0 fi # Step 3: Escalate -- need elevated permissions for remaining packages if command -v sudo >/dev/null 2>&1; then echo "" echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo " WARNING: We require sudo elevated permissions to install:" echo " $_STILL_MISSING" echo " If you accept, we'll run sudo now, and it'll prompt your password." echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo "" printf " Accept? [Y/n] " if [ -r /dev/tty ]; then read -r REPLY /dev/null; then OS="wsl" fi echo "==> Platform: $OS" # ── Check system dependencies ── # cmake and git are needed by unsloth studio setup to build the GGUF inference # engine (llama.cpp). build-essential and libcurl-dev are also needed on Linux. MISSING="" command -v cmake >/dev/null 2>&1 || MISSING="$MISSING cmake" command -v git >/dev/null 2>&1 || MISSING="$MISSING git" case "$OS" in macos) # Xcode Command Line Tools provide the C/C++ compiler if ! xcode-select -p >/dev/null 2>&1; then echo "" echo "==> Xcode Command Line Tools are required." echo " Installing (a system dialog will appear)..." xcode-select --install /dev/null || true echo " After the installation completes, please re-run this script." exit 1 fi ;; linux|wsl) # curl or wget is needed for downloads; check both if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then MISSING="$MISSING curl" fi command -v gcc >/dev/null 2>&1 || MISSING="$MISSING build-essential" # libcurl dev headers for llama.cpp HTTPS support if command -v dpkg >/dev/null 2>&1; then dpkg -s libcurl4-openssl-dev >/dev/null 2>&1 || MISSING="$MISSING libcurl4-openssl-dev" fi ;; esac MISSING=$(echo "$MISSING" | sed 's/^ *//') if [ -n "$MISSING" ]; then echo "" echo "==> Unsloth Studio needs these packages: $MISSING" echo " These are needed to build the GGUF inference engine." case "$OS" in macos) if ! command -v brew >/dev/null 2>&1; then echo "" echo " Homebrew is required to install them." echo " Install Homebrew from https://brew.sh then re-run this script." exit 1 fi brew install $MISSING /dev/null 2>&1; then _smart_apt_install $MISSING else echo " apt-get is not available. Please install with your package manager:" echo " $MISSING" echo " Then re-run Unsloth Studio setup." exit 1 fi ;; esac echo "" else echo "==> All system dependencies found." fi # ── Install uv ── if ! command -v uv >/dev/null 2>&1; then echo "==> Installing uv package manager..." _uv_tmp=$(mktemp) download "https://astral.sh/uv/install.sh" "$_uv_tmp" sh "$_uv_tmp" Creating Python ${PYTHON_VERSION} virtual environment (${VENV_NAME})..." uv venv "$VENV_NAME" --python "$PYTHON_VERSION" else echo "==> Virtual environment ${VENV_NAME} already exists, skipping creation." fi # ── Install unsloth directly into the venv (no activation needed) ── echo "==> Installing unsloth (this may take a few minutes)..." uv pip install --python "$VENV_NAME/bin/python" unsloth --torch-backend=auto # ── Run studio setup ── # Ensure the venv's Python is on PATH for setup.sh's Python discovery. # On macOS the system Python may be outside the 3.11-3.13 range that # setup.sh requires, but uv already installed a compatible interpreter # inside the venv. VENV_ABS_BIN="$(cd "$VENV_NAME/bin" && pwd)" if [ -n "$VENV_ABS_BIN" ]; then export PATH="$VENV_ABS_BIN:$PATH" fi echo "==> Running unsloth studio setup..." "$VENV_NAME/bin/unsloth" studio setup Launching Unsloth Studio..." echo "" exec "$VENV_NAME/bin/unsloth" studio -H 0.0.0.0 -p 8888 else echo " To launch, run:" echo "" echo " source ${VENV_NAME}/bin/activate" echo " unsloth studio -H 0.0.0.0 -p 8888" echo "" fi