-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Fix Install commands for Windows + 1 line installs #4447
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
b541102
e960400
62d1446
35abd87
3810fe6
9269d7a
fbb641e
3f1a4bc
7c8b7bf
bd0ae0d
aff4736
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # Unsloth Studio Installer for Windows PowerShell | ||
| # Usage: irm https://raw.githubusercontent.com/unslothai/unsloth/main/install.ps1 | iex | ||
| # Local: Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass; .\install.ps1 | ||
|
|
||
| function Install-UnslothStudio { | ||
| $ErrorActionPreference = "Stop" | ||
|
|
||
| $VenvName = "unsloth_studio" | ||
| $PythonVersion = "3.13" | ||
|
|
||
| Write-Host "" | ||
| Write-Host "=========================================" | ||
| Write-Host " Unsloth Studio Installer (Windows)" | ||
| Write-Host "=========================================" | ||
| Write-Host "" | ||
|
|
||
| # ── Helper: refresh PATH from registry (preserving current session entries) ── | ||
| function Refresh-SessionPath { | ||
| $machine = [System.Environment]::GetEnvironmentVariable("Path", "Machine") | ||
| $user = [System.Environment]::GetEnvironmentVariable("Path", "User") | ||
| $env:Path = "$machine;$user;$env:Path" | ||
| } | ||
|
|
||
| # ── Check winget ── | ||
| if (-not (Get-Command winget -ErrorAction SilentlyContinue)) { | ||
| Write-Host "Error: winget is not available." -ForegroundColor Red | ||
| Write-Host " Install it from https://aka.ms/getwinget" -ForegroundColor Yellow | ||
| Write-Host " or install Python $PythonVersion and uv manually, then re-run." -ForegroundColor Yellow | ||
| return | ||
| } | ||
|
|
||
| # ── Install Python 3.13 if no compatible Python found ── | ||
| # setup.ps1 accepts Python 3.11-3.13; we install 3.13 if nothing compatible is found | ||
| $NeedPython = $true | ||
| if (Get-Command python -ErrorAction SilentlyContinue) { | ||
| $pyVer = python --version 2>&1 | ||
| if ($pyVer -match "Python 3\.1[1-3]\.") { | ||
| Write-Host "==> Python already installed: $pyVer" | ||
| $NeedPython = $false | ||
| } | ||
| } | ||
| if ($NeedPython) { | ||
| Write-Host "==> Installing Python ${PythonVersion}..." | ||
| winget install -e --id Python.Python.3.13 --accept-package-agreements --accept-source-agreements | ||
| Refresh-SessionPath | ||
| } | ||
|
|
||
| # ── Install uv if not present ── | ||
| if (-not (Get-Command uv -ErrorAction SilentlyContinue)) { | ||
| Write-Host "==> Installing uv package manager..." | ||
| winget install --id=astral-sh.uv -e --accept-package-agreements --accept-source-agreements | ||
| Refresh-SessionPath | ||
| # Fallback: if winget didn't put uv on PATH, try the PowerShell installer | ||
| if (-not (Get-Command uv -ErrorAction SilentlyContinue)) { | ||
| Write-Host " Trying alternative uv installer..." | ||
| powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" | ||
| Refresh-SessionPath | ||
| } | ||
| } | ||
|
|
||
| if (-not (Get-Command uv -ErrorAction SilentlyContinue)) { | ||
| Write-Host "Error: uv could not be installed." -ForegroundColor Red | ||
| Write-Host " Install it from https://docs.astral.sh/uv/" -ForegroundColor Yellow | ||
| return | ||
| } | ||
|
|
||
| # ── Create venv (skip if it already exists) ── | ||
| $VenvPython = Join-Path $VenvName "Scripts\python.exe" | ||
| if (-not (Test-Path $VenvName)) { | ||
| Write-Host "==> Creating Python ${PythonVersion} virtual environment (${VenvName})..." | ||
| uv venv $VenvName --python $PythonVersion | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The installer marks Python 3.11–3.13 as compatible ( Useful? React with 👍 / 👎. |
||
| } else { | ||
| Write-Host "==> Virtual environment ${VenvName} already exists, skipping creation." | ||
| } | ||
|
|
||
| # ── Install unsloth directly into the venv (no activation needed) ── | ||
| Write-Host "==> Installing unsloth (this may take a few minutes)..." | ||
| uv pip install --python $VenvPython unsloth --torch-backend=auto | ||
|
|
||
| # ── Run studio setup ── | ||
| # setup.ps1 will handle installing Git, CMake, Visual Studio Build Tools, | ||
| # CUDA Toolkit, Node.js, and other dependencies automatically via winget. | ||
| Write-Host "==> Running unsloth studio setup..." | ||
| $UnslothExe = Join-Path $VenvName "Scripts\unsloth.exe" | ||
| & $UnslothExe studio setup | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This script relies on Useful? React with 👍 / 👎. |
||
|
|
||
| Write-Host "" | ||
| Write-Host "=========================================" | ||
| Write-Host " Unsloth Studio installed!" | ||
| Write-Host "=========================================" | ||
| Write-Host "" | ||
| Write-Host " To launch, run:" | ||
| Write-Host "" | ||
| Write-Host " .\${VenvName}\Scripts\activate" | ||
| Write-Host " unsloth studio -H 0.0.0.0 -p 8888" | ||
| Write-Host "" | ||
| } | ||
|
|
||
| Install-UnslothStudio | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| #!/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 | ||
| } | ||
|
|
||
| echo "" | ||
| echo "=========================================" | ||
| echo " Unsloth Studio Installer" | ||
| echo "=========================================" | ||
| echo "" | ||
|
|
||
| # ── Detect platform ── | ||
| OS="linux" | ||
| if [ "$(uname)" = "Darwin" ]; then | ||
| OS="macos" | ||
| elif grep -qi microsoft /proc/version 2>/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 2>/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 | ||
| printf " Install via Homebrew? [Y/n] " | ||
| read -r REPLY </dev/tty 2>/dev/null || REPLY="y" | ||
| case "$REPLY" in | ||
| [nN]*) echo " Skipping -- GGUF inference may not be available." ;; | ||
| *) brew install $MISSING ;; | ||
| esac | ||
| ;; | ||
| linux|wsl) | ||
| if command -v apt-get >/dev/null 2>&1; then | ||
| echo " We need elevated permissions (sudo) to install them." | ||
| printf " Allow? [Y/n] " | ||
| read -r REPLY </dev/tty 2>/dev/null || REPLY="y" | ||
| case "$REPLY" in | ||
| [nN]*) echo " Skipping -- GGUF inference may not be available." ;; | ||
| *) | ||
| sudo apt-get update -y | ||
| sudo apt-get install -y $MISSING | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In the Linux/WSL dependency install path, the script always runs Useful? React with 👍 / 👎. |
||
| ;; | ||
| esac | ||
| else | ||
| echo " Please install them with your package manager, then re-run." | ||
| fi | ||
|
Comment on lines
+160
to
+165
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When required packages are missing on Linux/WSL and Useful? React with 👍 / 👎. |
||
| ;; | ||
| 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" | ||
| rm -f "$_uv_tmp" | ||
| if [ -f "$HOME/.local/bin/env" ]; then | ||
| . "$HOME/.local/bin/env" | ||
| fi | ||
| export PATH="$HOME/.local/bin:$PATH" | ||
| fi | ||
|
|
||
| # ── Create venv (skip if it already exists) ── | ||
| if [ ! -d "$VENV_NAME" ]; then | ||
| echo "==> Creating Python ${PYTHON_VERSION} virtual environment (${VENV_NAME})..." | ||
| uv venv "$VENV_NAME" --python "$PYTHON_VERSION" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This installer always runs Useful? React with 👍 / 👎. |
||
| 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 ── | ||
| echo "==> Running unsloth studio setup..." | ||
| "$VENV_NAME/bin/unsloth" studio setup </dev/null | ||
|
|
||
| echo "" | ||
| echo "=========================================" | ||
| echo " Unsloth Studio installed!" | ||
| echo "=========================================" | ||
| echo "" | ||
| echo " To launch, run:" | ||
| echo "" | ||
| echo " source ${VENV_NAME}/bin/activate" | ||
| echo " unsloth studio -H 0.0.0.0 -p 8888" | ||
| echo "" | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This failure path returns from
Install-UnslothStudioinstead of terminating with a non-zero status, so callers can observe a successful command completion even when install prerequisites are missing. That matters for scripted installs (CI/bootstrap scripts) that rely on exit codes to detect failure. Usethrow/exit 1(or propagate an explicit non-zero return code) for fatal branches to avoid silent false-success outcomes.Useful? React with 👍 / 👎.