Merge pull request #154 from unslothai/feature/colab-notebook
Add Google Colab Support for Unsloth Studio
This commit is contained in:
commit
a243ea411d
3 changed files with 279 additions and 42 deletions
99
Unsloth_Studio_Colab.ipynb
Normal file
99
Unsloth_Studio_Colab.ipynb
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "447c1156",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# ===========================================\n",
|
||||
"# ⚠️ GPU Check - Run This First!\n",
|
||||
"# ===========================================\n",
|
||||
"import torch\n",
|
||||
"\n",
|
||||
"print(\"🔍 Checking for GPU...\")\n",
|
||||
"if not torch.cuda.is_available():\n",
|
||||
" print(\"❌ ERROR: No GPU detected!\")\n",
|
||||
" print(\"\\n📋 To enable GPU:\")\n",
|
||||
" print(\" 1. Go to: Runtime → Change runtime type\")\n",
|
||||
" print(\" 2. Select: Hardware accelerator → GPU (T4 is free)\")\n",
|
||||
" print(\" 3. Click: Save\")\n",
|
||||
" print(\" 4. Restart and re-run all cells\")\n",
|
||||
" raise RuntimeError(\"⛔ GPU required for Unsloth Studio\")\n",
|
||||
"else:\n",
|
||||
" gpu_name = torch.cuda.get_device_name(0)\n",
|
||||
" print(f\"✅ GPU detected: {gpu_name}\")\n",
|
||||
" print(\" Ready to proceed!\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f04a9b46",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# ===========================================\n",
|
||||
"# GitHub Authentication (Private Repo)\n",
|
||||
"# ===========================================\n",
|
||||
"from getpass import getpass\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"print(\"🔐 GitHub Token Required\")\n",
|
||||
"print(\"Get token: https://github.com/settings/tokens\")\n",
|
||||
"print(\"Scope needed: 'repo'\")\n",
|
||||
"print(\"-\" * 50)\n",
|
||||
"\n",
|
||||
"github_token = getpass(\"Enter GitHub Token: \")\n",
|
||||
"os.environ['GITHUB_TOKEN'] = github_token\n",
|
||||
"print(\"✅ Token stored\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "27e68f91",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# ===========================================\n",
|
||||
"# Setup: Clone repo and run setup\n",
|
||||
"# ===========================================\n",
|
||||
"\n",
|
||||
"import os\n",
|
||||
"github_token = os.environ['GITHUB_TOKEN']\n",
|
||||
"!git clone -b feature/colab-notebook https://{github_token}@github.com/unslothai/new-ui-prototype.git\n",
|
||||
"%cd /content/new-ui-prototype\n",
|
||||
"\n",
|
||||
"# Run setup script\n",
|
||||
"!chmod +x setup.sh\n",
|
||||
"!./setup.sh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "277e431e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# ===========================================\n",
|
||||
"# Start Unsloth Studio\n",
|
||||
"# ===========================================\n",
|
||||
"import sys\n",
|
||||
"sys.path.insert(0, '/content/new-ui-prototype/studio/backend')\n",
|
||||
"\n",
|
||||
"from colab import start\n",
|
||||
"start()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
132
setup.sh
132
setup.sh
|
|
@ -24,6 +24,13 @@ echo "╔═══════════════════════
|
|||
echo "║ Unsloth Studio Setup Script ║"
|
||||
echo "╚══════════════════════════════════════╝"
|
||||
|
||||
# ── Detect Colab (like unsloth does) ──
|
||||
IS_COLAB=false
|
||||
keynames=$'\n'$(printenv | cut -d= -f1)
|
||||
if [[ "$keynames" == *$'\nCOLAB_'* ]]; then
|
||||
IS_COLAB=true
|
||||
fi
|
||||
|
||||
# ── 1. Check existing Node/npm versions ──
|
||||
NEED_NODE=true
|
||||
if command -v node &>/dev/null && command -v npm &>/dev/null; then
|
||||
|
|
@ -33,7 +40,17 @@ if command -v node &>/dev/null && command -v npm &>/dev/null; then
|
|||
echo "✅ Node $(node -v) and npm $(npm -v) already meet requirements. Skipping nvm install."
|
||||
NEED_NODE=false
|
||||
else
|
||||
echo "⚠️ Node $(node -v) / npm $(npm -v) too old. Installing via nvm..."
|
||||
if [ "$IS_COLAB" = true ]; then
|
||||
echo "✅ Node $(node -v) and npm $(npm -v) detected in Colab."
|
||||
# In Colab, just upgrade npm directly - nvm doesn't work well
|
||||
if [ "$NPM_MAJOR" -lt 11 ]; then
|
||||
echo " Upgrading npm to latest..."
|
||||
npm install -g npm@latest > /dev/null 2>&1
|
||||
fi
|
||||
NEED_NODE=false
|
||||
else
|
||||
echo "⚠️ Node $(node -v) / npm $(npm -v) too old. Installing via nvm..."
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Node/npm not found. Installing via nvm..."
|
||||
|
|
@ -132,41 +149,61 @@ fi
|
|||
BEST_VER=$("$BEST_PY" --version 2>&1 | awk '{print $2}')
|
||||
echo "✅ Using $BEST_PY ($BEST_VER) — compatible (≤ 3.12.x)"
|
||||
|
||||
# Always start fresh to preserve correct install order
|
||||
rm -rf .venv
|
||||
"$BEST_PY" -m venv .venv
|
||||
source .venv/bin/activate
|
||||
run_quiet "pip upgrade" pip install --upgrade pip
|
||||
echo " Installing unsloth-zoo + unsloth..."
|
||||
run_quiet "pip install unsloth" pip install -r "$SCRIPT_DIR/studio/backend/requirements/base.txt"
|
||||
echo " Installing additional unsloth dependencies..."
|
||||
run_quiet "pip install extras" pip install --no-cache-dir -r "$SCRIPT_DIR/studio/backend/requirements/extras.txt"
|
||||
run_quiet "pip install extras" pip install --no-deps --no-cache-dir -r "$SCRIPT_DIR/studio/backend/requirements/extras-no-deps.txt"
|
||||
run_quiet "pip install torchao+transformers" pip install --force-reinstall --no-cache-dir -r "$SCRIPT_DIR/studio/backend/requirements/overrides.txt"
|
||||
run_quiet "pip install triton_kernels" pip install --no-deps -r "$SCRIPT_DIR/studio/backend/requirements/triton-kernels.txt"
|
||||
# Patch: override llama_cpp.py with fix from unsloth-zoo branch
|
||||
LLAMA_CPP_DST="$(pip show unsloth-zoo | grep -i '^Location:' | awk '{print $2}')/unsloth_zoo/llama_cpp.py"
|
||||
curl -sSL "https://raw.githubusercontent.com/unslothai/unsloth-zoo/refs/heads/main/unsloth_zoo/llama_cpp.py" \
|
||||
-o "$LLAMA_CPP_DST"
|
||||
echo " Installing studio dependencies..."
|
||||
run_quiet "pip install studio" pip install -r "$SCRIPT_DIR/studio/backend/requirements/studio.txt"
|
||||
echo "✅ Python dependencies installed"
|
||||
|
||||
# ── 7. WSL: pre-install GGUF build dependencies ──
|
||||
# On WSL, sudo requires a password and can't be entered during GGUF export
|
||||
# (runs in a non-interactive subprocess). Install build deps here instead.
|
||||
if grep -qi microsoft /proc/version 2>/dev/null; then
|
||||
echo ""
|
||||
echo "⚠️ WSL detected — installing build dependencies for GGUF export..."
|
||||
echo " You may be prompted for your password."
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y build-essential cmake curl git libcurl4-openssl-dev
|
||||
echo "✅ GGUF build dependencies installed"
|
||||
if [ "$IS_COLAB" = true ]; then
|
||||
# Colab: install packages directly without venv
|
||||
run_quiet "pip upgrade" pip install --upgrade pip
|
||||
echo " Installing unsloth-zoo + unsloth..."
|
||||
run_quiet "pip install unsloth" pip install -r "$SCRIPT_DIR/studio/backend/requirements/base.txt"
|
||||
echo " Installing additional unsloth dependencies..."
|
||||
run_quiet "pip install extras" pip install --no-cache-dir -r "$SCRIPT_DIR/studio/backend/requirements/extras.txt"
|
||||
run_quiet "pip install extras" pip install --no-deps --no-cache-dir -r "$SCRIPT_DIR/studio/backend/requirements/extras-no-deps.txt"
|
||||
run_quiet "pip install torchao+transformers" pip install --force-reinstall --no-cache-dir -r "$SCRIPT_DIR/studio/backend/requirements/overrides.txt"
|
||||
run_quiet "pip install triton_kernels" pip install --no-deps -r "$SCRIPT_DIR/studio/backend/requirements/triton-kernels.txt"
|
||||
# Patch: override llama_cpp.py with fix from unsloth-zoo branch
|
||||
LLAMA_CPP_DST="$(pip show unsloth-zoo | grep -i '^Location:' | awk '{print $2}')/unsloth_zoo/llama_cpp.py"
|
||||
curl -sSL "https://raw.githubusercontent.com/unslothai/unsloth-zoo/refs/heads/main/unsloth_zoo/llama_cpp.py" \
|
||||
-o "$LLAMA_CPP_DST"
|
||||
echo " Installing studio dependencies..."
|
||||
run_quiet "pip install studio" pip install -r "$SCRIPT_DIR/studio/backend/requirements/studio.txt"
|
||||
echo "✅ Python dependencies installed"
|
||||
else
|
||||
# Local: create venv (always start fresh to preserve correct install order)
|
||||
rm -rf .venv
|
||||
"$BEST_PY" -m venv .venv
|
||||
source .venv/bin/activate
|
||||
run_quiet "pip upgrade" pip install --upgrade pip
|
||||
echo " Installing unsloth-zoo + unsloth..."
|
||||
run_quiet "pip install unsloth" pip install -r "$SCRIPT_DIR/studio/backend/requirements/base.txt"
|
||||
echo " Installing additional unsloth dependencies..."
|
||||
run_quiet "pip install extras" pip install --no-cache-dir -r "$SCRIPT_DIR/studio/backend/requirements/extras.txt"
|
||||
run_quiet "pip install extras" pip install --no-deps --no-cache-dir -r "$SCRIPT_DIR/studio/backend/requirements/extras-no-deps.txt"
|
||||
run_quiet "pip install torchao+transformers" pip install --force-reinstall --no-cache-dir -r "$SCRIPT_DIR/studio/backend/requirements/overrides.txt"
|
||||
run_quiet "pip install triton_kernels" pip install --no-deps -r "$SCRIPT_DIR/studio/backend/requirements/triton-kernels.txt"
|
||||
# Patch: override llama_cpp.py with fix from unsloth-zoo branch
|
||||
LLAMA_CPP_DST="$(pip show unsloth-zoo | grep -i '^Location:' | awk '{print $2}')/unsloth_zoo/llama_cpp.py"
|
||||
curl -sSL "https://raw.githubusercontent.com/unslothai/unsloth-zoo/refs/heads/main/unsloth_zoo/llama_cpp.py" \
|
||||
-o "$LLAMA_CPP_DST"
|
||||
echo " Installing studio dependencies..."
|
||||
run_quiet "pip install studio" pip install -r "$SCRIPT_DIR/studio/backend/requirements/studio.txt"
|
||||
echo "✅ Python dependencies installed"
|
||||
|
||||
# ── 7. WSL: pre-install GGUF build dependencies ──
|
||||
# On WSL, sudo requires a password and can't be entered during GGUF export
|
||||
# (runs in a non-interactive subprocess). Install build deps here instead.
|
||||
if grep -qi microsoft /proc/version 2>/dev/null; then
|
||||
echo ""
|
||||
echo "⚠️ WSL detected — installing build dependencies for GGUF export..."
|
||||
echo " You may be prompted for your password."
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y build-essential cmake curl git libcurl4-openssl-dev
|
||||
echo "✅ GGUF build dependencies installed"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── 8. Add shell alias ──
|
||||
# ── 8. Add shell alias (skip in Colab) ──
|
||||
# Note: venv activation does NOT persist across terminal sessions.
|
||||
# This alias hardcodes the venv python path so users don't need to activate.
|
||||
if [ "$IS_COLAB" = false ]; then
|
||||
echo ""
|
||||
REPO_DIR="$SCRIPT_DIR"
|
||||
|
||||
|
|
@ -209,16 +246,27 @@ else
|
|||
echo "✅ Alias 'unsloth-ui' already exists in $SHELL_RC"
|
||||
fi
|
||||
|
||||
fi # End of "if not Colab" for shell alias setup
|
||||
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════╗"
|
||||
echo "║ Setup Complete! ║"
|
||||
echo "╠══════════════════════════════════════╣"
|
||||
if [ "$ALIAS_ADDED" = true ]; then
|
||||
echo "║ Run 'source $SHELL_RC'"
|
||||
echo "║ or open a new terminal, then: ║"
|
||||
if [ "$IS_COLAB" = true ]; then
|
||||
echo "╔══════════════════════════════════════╗"
|
||||
echo "║ Setup Complete! ║"
|
||||
echo "╠══════════════════════════════════════╣"
|
||||
echo "║ Unsloth Studio is ready to start ║"
|
||||
echo "║ in your Colab notebook! ║"
|
||||
echo "╚══════════════════════════════════════╝"
|
||||
else
|
||||
echo "║ Launch with: ║"
|
||||
echo "╔══════════════════════════════════════╗"
|
||||
echo "║ Setup Complete! ║"
|
||||
echo "╠══════════════════════════════════════╣"
|
||||
if [ "$ALIAS_ADDED" = true ]; then
|
||||
echo "║ Run 'source $SHELL_RC'"
|
||||
echo "║ or open a new terminal, then: ║"
|
||||
else
|
||||
echo "║ Launch with: ║"
|
||||
fi
|
||||
echo "║ ║"
|
||||
echo "║ unsloth-ui -H 0.0.0.0 -p 8000 ║"
|
||||
echo "╚══════════════════════════════════════╝"
|
||||
fi
|
||||
echo "║ ║"
|
||||
echo "║ unsloth-ui -H 0.0.0.0 -p 8000 ║"
|
||||
echo "╚══════════════════════════════════════╝"
|
||||
|
|
|
|||
90
studio/backend/colab.py
Normal file
90
studio/backend/colab.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"""
|
||||
Colab-specific helpers for running Unsloth Studio.
|
||||
Uses Colab's built-in proxy - no external tunneling needed!
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_colab_url(port: int = 8000) -> str:
|
||||
"""
|
||||
Get the actual Colab proxy URL for a port.
|
||||
"""
|
||||
try:
|
||||
from google.colab.output import eval_js
|
||||
|
||||
# Use Colab's proxy mechanism
|
||||
url = eval_js(f"google.colab.kernel.proxyPort({port})", timeout_sec=5)
|
||||
return url if url else f"http://localhost:{port}"
|
||||
except Exception as e:
|
||||
print(f"Note: Could not get Colab URL ({e})")
|
||||
return f"http://localhost:{port}"
|
||||
|
||||
|
||||
def show_link(port: int = 8000):
|
||||
"""Display a styled clickable link to the UI."""
|
||||
from IPython.display import display, HTML
|
||||
|
||||
# Get real Colab proxy URL
|
||||
url = get_colab_url(port)
|
||||
|
||||
html = f"""
|
||||
<div style="padding: 20px; background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
|
||||
border-radius: 12px; margin: 10px 0; font-family: system-ui, -apple-system, sans-serif;">
|
||||
<h2 style="color: white; margin: 0 0 12px 0; font-size: 24px;">
|
||||
🦥 Unsloth Studio is Ready!
|
||||
</h2>
|
||||
<a href="{url}" target="_blank"
|
||||
style="display: inline-block; padding: 14px 28px; background: white; color: #16a34a;
|
||||
text-decoration: none; border-radius: 8px; font-weight: 600; font-size: 16px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
|
||||
🚀 Open Unsloth Studio
|
||||
</a>
|
||||
<p style="color: rgba(255,255,255,0.9); margin: 16px 0 0 0; font-size: 13px;
|
||||
word-break: break-all; font-family: monospace;">
|
||||
{url}
|
||||
</p>
|
||||
</div>
|
||||
"""
|
||||
display(HTML(html))
|
||||
|
||||
|
||||
def start(port: int = 8000):
|
||||
"""
|
||||
Start Unsloth Studio server in Colab and display the URL.
|
||||
|
||||
Usage:
|
||||
from colab import start
|
||||
start()
|
||||
"""
|
||||
import sys
|
||||
|
||||
print("🦥 Starting Unsloth Studio...")
|
||||
|
||||
# Add backend to path
|
||||
backend_path = str(Path(__file__).parent)
|
||||
if backend_path not in sys.path:
|
||||
sys.path.insert(0, backend_path)
|
||||
|
||||
print(" Loading backend...")
|
||||
from run import run_server
|
||||
|
||||
# Auto-detect frontend path
|
||||
repo_root = Path(__file__).parent.parent
|
||||
frontend_path = repo_root / "frontend" / "dist"
|
||||
|
||||
if not frontend_path.exists():
|
||||
print("❌ Frontend not built! Please run the setup cell first.")
|
||||
return
|
||||
|
||||
print(" Starting server...")
|
||||
# Start server silently
|
||||
run_server(host="0.0.0.0", port=port, frontend_path=frontend_path, silent=True)
|
||||
|
||||
print(" Server started!")
|
||||
|
||||
# Show the clickable link with real URL
|
||||
show_link(port)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
start()
|
||||
Loading…
Add table
Add a link
Reference in a new issue