Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ad9d622
Allow Windows setup to complete without NVIDIA GPU
danielhanchen Mar 18, 2026
1f075a9
Cache frontend build across setup runs
danielhanchen Mar 18, 2026
a7d4e88
Show pip progress for PyTorch download on Windows
danielhanchen Mar 18, 2026
c53f529
Guard CUDA env re-sanitization behind GPU check in llama.cpp build
danielhanchen Mar 18, 2026
5e36f09
Rebuild frontend when source files are newer than dist/
danielhanchen Mar 18, 2026
be61a34
Fix cmake not found on Windows after winget install
danielhanchen Mar 18, 2026
153c203
Fix frontend rebuild detection and decouple oxc-validator install
danielhanchen Mar 18, 2026
c2f1222
Show cmake errors on failure and retry CUDA VS integration with eleva…
danielhanchen Mar 18, 2026
4f1e9df
Address reviewer feedback: cmake PATH persistence, stale cache, torch…
danielhanchen Mar 18, 2026
7125772
Remove extra CUDA cmake flags to align Windows with Linux build
danielhanchen Mar 18, 2026
8035e9c
Address reviewer round 2: GPU probe fallback, Triton check, stale bin…
danielhanchen Mar 18, 2026
2b1e53d
Fix frontend rebuild detection and npm dependency issues
danielhanchen Mar 18, 2026
f43091b
Merge branch 'main' into fix/studio-venv-colab
danielhanchen Mar 18, 2026
fc2d577
Fix studio setup: venv isolation, centralized .venv_t5, uv targeting
danielhanchen Mar 18, 2026
ce80c3f
Merge branch 'main' into fix/windows-setup-no-gpu
danielhanchen Mar 18, 2026
446f829
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 18, 2026
69d99a4
Fix nvidia-smi PATH persistence and cmake requirement for CPU-only
danielhanchen Mar 18, 2026
bd7299e
Fix broken frontend freshness detection in setup scripts
danielhanchen Mar 18, 2026
9e1a6b4
Merge remote-tracking branch 'origin/fix/windows-setup-no-gpu' into c…
danielhanchen Mar 18, 2026
15c93e6
Fix bugs found during review of PRs #4404, #4400, #4399
danielhanchen Mar 18, 2026
a0f5b0a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 18, 2026
9e7e638
Fix _venv_t5_is_valid dist-info loop exiting after first directory
danielhanchen Mar 18, 2026
a6aeb53
Capture error output on failure instead of discarding with Out-Null
danielhanchen Mar 18, 2026
c58bcd5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 18, 2026
3bca3c3
Fix ModuleNotFoundError when CLI imports studio.backend.core
danielhanchen Mar 18, 2026
f9e963e
Fix frontend freshness check to detect all top-level file changes
danielhanchen Mar 18, 2026
0c4b2bf
Add tiktoken to .venv_t5 for Qwen-family tokenizers
danielhanchen Mar 18, 2026
27df466
Merge branch 'main' into combined/studio-setup-fixes
danielhanchen Mar 18, 2026
bcd43ed
Fix tiktoken crash in _venv_t5_is_valid and stray brace in setup.ps1
danielhanchen Mar 18, 2026
721577b
Merge branch 'main' into combined/studio-setup-fixes
danielhanchen Mar 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions studio/backend/colab.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,31 @@
from pathlib import Path
import sys


def _bootstrap_studio_venv() -> None:
"""Expose the Studio venv's site-packages to the current interpreter.

On Colab, notebook cells run outside the venv subshell. Instead of
installing the full stack into system Python, we prepend the venv's
site-packages so that packages like structlog, fastapi, etc. are
importable from notebook cells and take priority over system copies.
"""
venv_lib = Path.home() / ".unsloth" / "studio" / ".venv" / "lib"
if not venv_lib.exists():
import warnings
warnings.warn(
f"Studio venv not found at {venv_lib.parent} -- run 'unsloth studio setup' first",
stacklevel=2,
)
return
for sp in venv_lib.glob("python*/site-packages"):
sp_str = str(sp)
if sp_str not in sys.path:
sys.path.insert(0, sp_str)


_bootstrap_studio_venv()

# Add backend to path early so local modules like loggers can be imported
backend_path = str(Path(__file__).parent)
if backend_path not in sys.path:
Expand Down
60 changes: 13 additions & 47 deletions studio/backend/core/export/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,59 +40,25 @@ def _activate_transformers_version(model_name: str) -> None:
if backend_path not in sys.path:
sys.path.insert(0, backend_path)

from utils.transformers_version import needs_transformers_5, _resolve_base_model
from utils.transformers_version import (
needs_transformers_5,
_resolve_base_model,
_ensure_venv_t5_exists,
_VENV_T5_DIR,
)

resolved = _resolve_base_model(model_name)
if needs_transformers_5(resolved):
venv_t5 = os.path.join(
os.path.expanduser("~"), ".unsloth", "studio", ".venv_t5"
)
if os.path.isdir(venv_t5):
sys.path.insert(0, venv_t5)
logger.info("Activated transformers 5.x from %s", venv_t5)
else:
# Fallback: pip install at runtime (slower, ~10-15s)
logger.warning(".venv_t5 not found at %s — installing at runtime", venv_t5)
import subprocess as sp

os.makedirs(venv_t5, exist_ok = True)
r1 = sp.run(
[
sys.executable,
"-m",
"pip",
"install",
"--target",
venv_t5,
"--no-deps",
"transformers==5.3.0",
],
stdout = sp.PIPE,
stderr = sp.STDOUT,
if not _ensure_venv_t5_exists():
raise RuntimeError(
f"Cannot activate transformers 5.x: .venv_t5 missing at {_VENV_T5_DIR}"
)
r2 = sp.run(
[
sys.executable,
"-m",
"pip",
"install",
"--target",
venv_t5,
"--no-deps",
"huggingface_hub==1.3.0",
],
stdout = sp.PIPE,
stderr = sp.STDOUT,
)
if r1.returncode != 0 or r2.returncode != 0:
raise RuntimeError(
f"Failed to install transformers 5.x into {venv_t5}. "
f"pip returncode: transformers={r1.returncode}, huggingface_hub={r2.returncode}"
)
sys.path.insert(0, venv_t5)
if _VENV_T5_DIR not in sys.path:
sys.path.insert(0, _VENV_T5_DIR)
logger.info("Activated transformers 5.x from %s", _VENV_T5_DIR)
# Propagate to child subprocesses (e.g. GGUF converter)
_pp = os.environ.get("PYTHONPATH", "")
os.environ["PYTHONPATH"] = venv_t5 + (os.pathsep + _pp if _pp else "")
os.environ["PYTHONPATH"] = _VENV_T5_DIR + (os.pathsep + _pp if _pp else "")
else:
logger.info("Using default transformers (4.57.x) for %s", model_name)

Expand Down
60 changes: 13 additions & 47 deletions studio/backend/core/inference/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,59 +42,25 @@ def _activate_transformers_version(model_name: str) -> None:
if backend_path not in sys.path:
sys.path.insert(0, backend_path)

from utils.transformers_version import needs_transformers_5, _resolve_base_model
from utils.transformers_version import (
needs_transformers_5,
_resolve_base_model,
_ensure_venv_t5_exists,
_VENV_T5_DIR,
)

resolved = _resolve_base_model(model_name)
if needs_transformers_5(resolved):
venv_t5 = os.path.join(
os.path.expanduser("~"), ".unsloth", "studio", ".venv_t5"
)
if os.path.isdir(venv_t5):
sys.path.insert(0, venv_t5)
logger.info("Activated transformers 5.x from %s", venv_t5)
else:
# Fallback: pip install at runtime (slower, ~10-15s)
logger.warning(".venv_t5 not found at %s — installing at runtime", venv_t5)
import subprocess as sp

os.makedirs(venv_t5, exist_ok = True)
r1 = sp.run(
[
sys.executable,
"-m",
"pip",
"install",
"--target",
venv_t5,
"--no-deps",
"transformers==5.3.0",
],
stdout = sp.PIPE,
stderr = sp.STDOUT,
if not _ensure_venv_t5_exists():
raise RuntimeError(
f"Cannot activate transformers 5.x: .venv_t5 missing at {_VENV_T5_DIR}"
)
r2 = sp.run(
[
sys.executable,
"-m",
"pip",
"install",
"--target",
venv_t5,
"--no-deps",
"huggingface_hub==1.3.0",
],
stdout = sp.PIPE,
stderr = sp.STDOUT,
)
if r1.returncode != 0 or r2.returncode != 0:
raise RuntimeError(
f"Failed to install transformers 5.x into {venv_t5}. "
f"pip returncode: transformers={r1.returncode}, huggingface_hub={r2.returncode}"
)
sys.path.insert(0, venv_t5)
if _VENV_T5_DIR not in sys.path:
sys.path.insert(0, _VENV_T5_DIR)
logger.info("Activated transformers 5.x from %s", _VENV_T5_DIR)
# Propagate to child subprocesses (e.g. GGUF converter)
_pp = os.environ.get("PYTHONPATH", "")
os.environ["PYTHONPATH"] = venv_t5 + (os.pathsep + _pp if _pp else "")
os.environ["PYTHONPATH"] = _VENV_T5_DIR + (os.pathsep + _pp if _pp else "")
else:
logger.info("Using default transformers (4.57.x) for %s", model_name)

Expand Down
60 changes: 13 additions & 47 deletions studio/backend/core/training/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,59 +36,25 @@ def _activate_transformers_version(model_name: str) -> None:
if backend_path not in sys.path:
sys.path.insert(0, backend_path)

from utils.transformers_version import needs_transformers_5, _resolve_base_model
from utils.transformers_version import (
needs_transformers_5,
_resolve_base_model,
_ensure_venv_t5_exists,
_VENV_T5_DIR,
)

resolved = _resolve_base_model(model_name)
if needs_transformers_5(resolved):
venv_t5 = os.path.join(
os.path.expanduser("~"), ".unsloth", "studio", ".venv_t5"
)
if os.path.isdir(venv_t5):
sys.path.insert(0, venv_t5)
logger.info("Activated transformers 5.x from %s", venv_t5)
else:
# Fallback: pip install at runtime (slower, ~10-15s)
logger.warning(".venv_t5 not found at %s — installing at runtime", venv_t5)
import subprocess as sp

os.makedirs(venv_t5, exist_ok = True)
r1 = sp.run(
[
sys.executable,
"-m",
"pip",
"install",
"--target",
venv_t5,
"--no-deps",
"transformers==5.3.0",
],
stdout = sp.PIPE,
stderr = sp.STDOUT,
if not _ensure_venv_t5_exists():
raise RuntimeError(
f"Cannot activate transformers 5.x: .venv_t5 missing at {_VENV_T5_DIR}"
)
r2 = sp.run(
[
sys.executable,
"-m",
"pip",
"install",
"--target",
venv_t5,
"--no-deps",
"huggingface_hub==1.3.0",
],
stdout = sp.PIPE,
stderr = sp.STDOUT,
)
if r1.returncode != 0 or r2.returncode != 0:
raise RuntimeError(
f"Failed to install transformers 5.x into {venv_t5}. "
f"pip returncode: transformers={r1.returncode}, huggingface_hub={r2.returncode}"
)
sys.path.insert(0, venv_t5)
if _VENV_T5_DIR not in sys.path:
sys.path.insert(0, _VENV_T5_DIR)
logger.info("Activated transformers 5.x from %s", _VENV_T5_DIR)
# Propagate to child subprocesses (e.g. GGUF converter)
_pp = os.environ.get("PYTHONPATH", "")
os.environ["PYTHONPATH"] = venv_t5 + (os.pathsep + _pp if _pp else "")
os.environ["PYTHONPATH"] = _VENV_T5_DIR + (os.pathsep + _pp if _pp else "")
else:
logger.info("Using default transformers (4.57.x) for %s", model_name)

Expand Down
2 changes: 1 addition & 1 deletion studio/backend/requirements/extras-no-deps.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ git+https://github.com/meta-pytorch/OpenEnv.git
# executorch>=1.0.1 # 41.5 MB - no imports in unsloth/zoo/studio
torch-c-dlpack-ext
sentence_transformers==5.2.0
transformers==4.57.1
transformers==4.57.6
2 changes: 1 addition & 1 deletion studio/backend/requirements/single-env/constraints.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Single-env pins for unsloth + studio + data-designer
# Keep compatible with unsloth transformers bounds.
transformers==4.57.1
transformers==4.57.6
trl==0.23.1
huggingface-hub==0.36.2

Expand Down
Loading
Loading