diff --git a/install.sh b/install.sh index d12abe298f..49bb7a7b89 100755 --- a/install.sh +++ b/install.sh @@ -1290,6 +1290,14 @@ if [ "$_NO_TORCH_FLAG" = true ] || [ "$MAC_INTEL" = true ]; then SKIP_TORCH=true fi +# Apple Silicon: override mlx-vlm / mlx-lm's transformers pin (see overrides file). +if [ "$OS" = "macos" ] && [ "$_ARCH" = "arm64" ]; then + _OVERRIDES_FILE="$(cd "$(dirname "$0" 2>/dev/null || echo ".")" && pwd)/studio/backend/requirements/single-env/overrides-darwin-arm64.txt" + if [ -f "$_OVERRIDES_FILE" ]; then + export UV_OVERRIDE="$_OVERRIDES_FILE" + fi +fi + _TAURI_INITIAL_GPU_BRANCH="unknown" if [ "$SKIP_TORCH" = true ]; then _TAURI_INITIAL_GPU_BRANCH="no_torch" @@ -2108,12 +2116,6 @@ else fi fi -# ── Install mlx-vlm on Apple Silicon (optional, for VLM training) ── -if [ "$OS" = "macos" ] && [ "$_ARCH" = "arm64" ]; then - substep "installing mlx-vlm (VLM training support)..." - run_install_cmd "install mlx-vlm" uv pip install --python "$_VENV_PY" mlx-vlm -fi - # ── Run studio setup ── tauri_log "STEP" "Running Studio setup" # When --local, use the repo's own setup.sh directly. diff --git a/studio/backend/requirements/single-env/overrides-darwin-arm64.txt b/studio/backend/requirements/single-env/overrides-darwin-arm64.txt new file mode 100644 index 0000000000..2cd03d8b78 --- /dev/null +++ b/studio/backend/requirements/single-env/overrides-darwin-arm64.txt @@ -0,0 +1,5 @@ +# mlx-vlm / mlx-lm declare transformers>=5.x which conflicts with the +# main venv's constraints.txt pin transformers==4.57.6 and forces uv to +# backtrack unsloth. Relax to match the pin -- per-model 5.x routing +# happens at runtime via the side-car venvs. +transformers>=4.57.6 diff --git a/studio/backend/utils/hardware/hardware.py b/studio/backend/utils/hardware/hardware.py index 3764e38272..ede37e2953 100644 --- a/studio/backend/utils/hardware/hardware.py +++ b/studio/backend/utils/hardware/hardware.py @@ -144,7 +144,10 @@ def detect_hardware() -> DeviceType: if is_apple_silicon() and _has_mlx(): DEVICE = DeviceType.MLX CHAT_ONLY = False - chip = platform.processor() or platform.machine() + # platform.processor() runs `uname -p` which returns "i386" on most + # universal2 / Rosetta-shaped Python builds even on native arm64. + # platform.machine() is "arm64" once is_apple_silicon() has gated us. + chip = platform.machine() or "arm64" print(f"Hardware detected: MLX — Apple Silicon ({chip})") return DEVICE @@ -279,13 +282,11 @@ def get_gpu_memory_info() -> Dict[str, Any]: try: info = mx.device_info() - gpu_name = ( - info.get("device_name") - or platform.processor() - or platform.machine() - ) + # See detect_hardware(): platform.processor() can return "i386" + # on native arm64 Python builds, so prefer machine() as fallback. + gpu_name = info.get("device_name") or platform.machine() or "arm64" except Exception: - gpu_name = platform.processor() or platform.machine() + gpu_name = platform.machine() or "arm64" return { "available": True, diff --git a/studio/install_python_stack.py b/studio/install_python_stack.py index 9166d35ce3..ca7fe3f004 100644 --- a/studio/install_python_stack.py +++ b/studio/install_python_stack.py @@ -37,6 +37,7 @@ from backend.utils.wheel_utils import ( IS_WINDOWS = sys.platform == "win32" IS_MACOS = sys.platform == "darwin" IS_MAC_INTEL = IS_MACOS and platform.machine() == "x86_64" +IS_MAC_ARM = IS_MACOS and platform.machine() == "arm64" # ── ROCm / AMD GPU support ───────────────────────────────────────────────────── # Mapping from detected ROCm (major, minor) to the best PyTorch wheel tag on @@ -423,6 +424,7 @@ def _infer_no_torch() -> bool: NO_TORCH = _infer_no_torch() + # -- Verbosity control ---------------------------------------------------------- # By default the installer shows a minimal progress bar (one line, in-place). # Set UNSLOTH_VERBOSE=1 in the environment to restore full per-step output: @@ -448,6 +450,11 @@ LOCAL_DD_GITHUB_PLUGIN = ( SCRIPT_DIR / "backend" / "plugins" / "data-designer-github-repo-seed" ) +# Apple Silicon: override mlx-vlm/mlx-lm's transformers pin (see overrides file). +_MLX_OVERRIDES = SINGLE_ENV / "overrides-darwin-arm64.txt" +if IS_MAC_ARM and _MLX_OVERRIDES.is_file(): + os.environ.setdefault("UV_OVERRIDE", str(_MLX_OVERRIDES)) + # -- Unicode-safe printing --------------------------------------------- # On Windows the default console encoding can be a legacy code page # (e.g. CP1252) that cannot represent Unicode glyphs such as ✅ or ❌. @@ -960,6 +967,20 @@ def install_python_stack() -> int: [sys.executable, "-m", "pip", "install", "--upgrade", "pip"], ) + # macOS arm64: install MLX stack at latest (UV_OVERRIDE relaxes the + # mlx-vlm / mlx-lm transformers pin -- set at module load). + if IS_MAC_ARM and not skip_base: + _progress("MLX stack (Apple Silicon)") + pip_install( + "Installing MLX stack (mlx + mlx-lm + mlx-vlm)", + "--no-cache-dir", + "--upgrade", + "mlx", + "mlx-metal", + "mlx-lm", + "mlx-vlm", + ) + # 3. Core packages: unsloth-zoo + unsloth (or custom package name) if skip_base: pass