chore: import upstream snapshot with attribution
Lockfile supply-chain audit / lockfile supply-chain audit (push) Has been cancelled
Windows Studio GGUF CI / GPU prebuilt resolves without Visual Studio (push) Has been cancelled
Windows Studio GGUF CI / setup.ps1 unit tests (VS 2026 / CMake guard) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2022) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-2025-vs2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-latest) (push) Has been cancelled
Windows Studio Update CI / Studio Updating Tests (push) Has been cancelled
Wheel CI / Wheel build + content sanity + import smoke (push) Has been cancelled
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Has been cancelled
MLX CI on Mac M1 / dispatch (push) Has been cancelled
Security audit / advisory audit (pip + npm + cargo) (push) Has been cancelled
Security audit / pip scan-packages :: extras (push) Has been cancelled
Security audit / pip scan-packages :: studio (push) Has been cancelled
Security audit / pip scan-packages :: hf-stack (push) Has been cancelled
Security audit / npm scan-packages (Studio frontend tarballs) (push) Has been cancelled
Security audit / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Has been cancelled
Security audit / pytest tests/security (push) Has been cancelled
Security audit / npm provenance + new install-script diff (push) Has been cancelled
Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Backend CI / (Python 3.10) (push) Has been cancelled
Backend CI / (Python 3.11) (push) Has been cancelled
Backend CI / (Python 3.12) (push) Has been cancelled
Backend CI / (Python 3.13) (push) Has been cancelled
Backend CI / Repo tests (CPU) (push) Has been cancelled
Frontend CI / Frontend build + bundle sanity (push) Has been cancelled
Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Mac Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Mac Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-14) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15-intel) (push) Has been cancelled
Mac Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26-intel) (push) Has been cancelled
Mac Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Tauri CI / Tauri Linux debug build (no codesign) (push) Has been cancelled
Mac Studio Update CI / Studio Updating Tests (push) Has been cancelled
Studio UI CI / Chat UI Tests (push) Has been cancelled
Windows Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Windows Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Update CI / Studio Updating Tests (push) Has been cancelled
Core / Core (HF=default + TRL=default) (push) Has been cancelled
Core / Core (HF=4.57.6 + TRL<1) (push) Has been cancelled
Core / Core (HF=latest + TRL=latest) (push) Has been cancelled
Core / llama.cpp build + smoke (push) Has been cancelled
Windows Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Windows Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Windows Studio GGUF CI / JSON, images (push) Has been cancelled
Windows Studio GGUF CI / Studio install + inference without Visual Studio (push) Has been cancelled
Studio export capability / capability (macos-latest) (push) Has been cancelled
Studio export capability / capability (ubuntu-latest) (push) Has been cancelled
Studio export capability / capability (windows-latest) (push) Has been cancelled
Cross-platform parity / parity (macos-latest) (push) Has been cancelled
Cross-platform parity / parity (windows-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Studio load-orchestrator CI / test (push) Has been cancelled
Lockfile supply-chain audit / lockfile supply-chain audit (push) Has been cancelled
Windows Studio GGUF CI / GPU prebuilt resolves without Visual Studio (push) Has been cancelled
Windows Studio GGUF CI / setup.ps1 unit tests (VS 2026 / CMake guard) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2022) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-2025-vs2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-latest) (push) Has been cancelled
Windows Studio Update CI / Studio Updating Tests (push) Has been cancelled
Wheel CI / Wheel build + content sanity + import smoke (push) Has been cancelled
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Has been cancelled
MLX CI on Mac M1 / dispatch (push) Has been cancelled
Security audit / advisory audit (pip + npm + cargo) (push) Has been cancelled
Security audit / pip scan-packages :: extras (push) Has been cancelled
Security audit / pip scan-packages :: studio (push) Has been cancelled
Security audit / pip scan-packages :: hf-stack (push) Has been cancelled
Security audit / npm scan-packages (Studio frontend tarballs) (push) Has been cancelled
Security audit / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Has been cancelled
Security audit / pytest tests/security (push) Has been cancelled
Security audit / npm provenance + new install-script diff (push) Has been cancelled
Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Backend CI / (Python 3.10) (push) Has been cancelled
Backend CI / (Python 3.11) (push) Has been cancelled
Backend CI / (Python 3.12) (push) Has been cancelled
Backend CI / (Python 3.13) (push) Has been cancelled
Backend CI / Repo tests (CPU) (push) Has been cancelled
Frontend CI / Frontend build + bundle sanity (push) Has been cancelled
Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Mac Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Mac Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-14) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15-intel) (push) Has been cancelled
Mac Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26-intel) (push) Has been cancelled
Mac Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Tauri CI / Tauri Linux debug build (no codesign) (push) Has been cancelled
Mac Studio Update CI / Studio Updating Tests (push) Has been cancelled
Studio UI CI / Chat UI Tests (push) Has been cancelled
Windows Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Windows Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Update CI / Studio Updating Tests (push) Has been cancelled
Core / Core (HF=default + TRL=default) (push) Has been cancelled
Core / Core (HF=4.57.6 + TRL<1) (push) Has been cancelled
Core / Core (HF=latest + TRL=latest) (push) Has been cancelled
Core / llama.cpp build + smoke (push) Has been cancelled
Windows Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Windows Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Windows Studio GGUF CI / JSON, images (push) Has been cancelled
Windows Studio GGUF CI / Studio install + inference without Visual Studio (push) Has been cancelled
Studio export capability / capability (macos-latest) (push) Has been cancelled
Studio export capability / capability (ubuntu-latest) (push) Has been cancelled
Studio export capability / capability (windows-latest) (push) Has been cancelled
Cross-platform parity / parity (macos-latest) (push) Has been cancelled
Cross-platform parity / parity (windows-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Studio load-orchestrator CI / test (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
"""Shared backend utilities."""
|
||||
|
||||
import os
|
||||
import structlog
|
||||
from loggers import get_logger
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
# ── Client-safe error helpers ───────────────────────────────────
|
||||
# Never return raw exception text to clients; log server-side, return generic.
|
||||
|
||||
|
||||
def safe_error_detail(error: Exception, fallback: str = "An internal error occurred") -> str:
|
||||
"""Map an exception to a generic, client-safe message (never raw
|
||||
``str(error)``, which can leak paths). Log the real exception server-side.
|
||||
"""
|
||||
text = str(error).lower()
|
||||
if (
|
||||
isinstance(error, (ConnectionError, TimeoutError))
|
||||
or "connection" in text
|
||||
or "timed out" in text
|
||||
or "timeout" in text
|
||||
):
|
||||
return "Could not reach an upstream service. Please try again."
|
||||
if "out of memory" in text or "cuda error" in text:
|
||||
return "Ran out of memory. Try a smaller model or shorter input."
|
||||
return fallback
|
||||
|
||||
|
||||
def safe_curated_detail(error: Exception, fallback: str = "An internal error occurred") -> str:
|
||||
"""Client-safe text for curated domain/validation exceptions.
|
||||
|
||||
Keeps the message (paths stripped) instead of a generic fallback; for known
|
||||
exception types only (use ``safe_error_detail`` for generic ``Exception``).
|
||||
"""
|
||||
from utils.native_path_leases import redact_native_paths
|
||||
|
||||
msg = redact_native_paths(str(error)).strip()
|
||||
return msg or fallback
|
||||
|
||||
|
||||
def log_and_http_error(
|
||||
error: Exception,
|
||||
status_code: int,
|
||||
public_message: str,
|
||||
*,
|
||||
event: str = "request_failed",
|
||||
log = None,
|
||||
):
|
||||
"""Log ``error`` in full server-side and return an ``HTTPException`` whose
|
||||
``detail`` is only ``public_message`` -- never the raw exception text.
|
||||
|
||||
Usage: raise log_and_http_error(e, 500, "Failed to start training")
|
||||
"""
|
||||
from fastapi import HTTPException
|
||||
|
||||
# exc_info=error works for both structlog and stdlib loggers.
|
||||
(log or logger).error(f"{event}: {error}", exc_info = error)
|
||||
return HTTPException(status_code = status_code, detail = public_message)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def without_hf_auth():
|
||||
"""
|
||||
Temporarily disable HuggingFace authentication.
|
||||
|
||||
Usage:
|
||||
with without_hf_auth():
|
||||
# Code that should run without cached tokens
|
||||
model_info(model_name, token=None)
|
||||
"""
|
||||
saved_env = {}
|
||||
env_vars = ["HF_TOKEN", "HUGGINGFACE_HUB_TOKEN", "HF_HOME"]
|
||||
for var in env_vars:
|
||||
if var in os.environ:
|
||||
saved_env[var] = os.environ[var]
|
||||
del os.environ[var]
|
||||
|
||||
saved_disable = os.environ.get("HF_HUB_DISABLE_IMPLICIT_TOKEN")
|
||||
os.environ["HF_HUB_DISABLE_IMPLICIT_TOKEN"] = "1"
|
||||
|
||||
# Move token files aside temporarily
|
||||
token_files = []
|
||||
token_locations = [
|
||||
Path.home() / ".cache" / "huggingface" / "token",
|
||||
Path.home() / ".huggingface" / "token",
|
||||
]
|
||||
|
||||
for token_loc in token_locations:
|
||||
if token_loc.exists():
|
||||
temp = tempfile.NamedTemporaryFile(delete = False)
|
||||
temp.close()
|
||||
shutil.move(str(token_loc), temp.name)
|
||||
token_files.append((token_loc, temp.name))
|
||||
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
# Restore tokens
|
||||
for original, temp in token_files:
|
||||
try:
|
||||
original.parent.mkdir(parents = True, exist_ok = True)
|
||||
shutil.move(temp, str(original))
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to restore token {original}: {e}")
|
||||
|
||||
# Restore env
|
||||
for var, value in saved_env.items():
|
||||
os.environ[var] = value
|
||||
|
||||
if saved_disable is not None:
|
||||
os.environ["HF_HUB_DISABLE_IMPLICIT_TOKEN"] = saved_disable
|
||||
else:
|
||||
os.environ.pop("HF_HUB_DISABLE_IMPLICIT_TOKEN", None)
|
||||
|
||||
|
||||
def format_error_message(error: Exception, model_name: str) -> str:
|
||||
"""
|
||||
Format a user-friendly error message for common load issues.
|
||||
|
||||
Args:
|
||||
error: The exception that occurred
|
||||
model_name: Name of the model being loaded
|
||||
"""
|
||||
error_str = str(error).lower()
|
||||
model_short = model_name.split("/")[-1] if "/" in model_name else model_name
|
||||
|
||||
if "repository not found" in error_str or "404" in error_str:
|
||||
return f"Model '{model_short}' not found. Check the model name."
|
||||
|
||||
if "401" in error_str or "unauthorized" in error_str:
|
||||
return f"Authentication failed for '{model_short}'. Please provide a valid HF token."
|
||||
|
||||
if "gated" in error_str or "access to model" in error_str:
|
||||
return f"Model '{model_short}' requires authentication. Please provide a valid HF token."
|
||||
|
||||
if "invalid user token" in error_str:
|
||||
return "Invalid HF token. Please check your token and try again."
|
||||
|
||||
if (
|
||||
"memory" in error_str
|
||||
or "cuda" in error_str
|
||||
or "mlx" in error_str
|
||||
or "out of memory" in error_str
|
||||
):
|
||||
from utils.hardware import get_device
|
||||
|
||||
device = get_device()
|
||||
device_label = {"cuda": "GPU", "mlx": "Apple Silicon GPU", "cpu": "system"}.get(
|
||||
device.value, "GPU"
|
||||
)
|
||||
return f"Not enough {device_label} memory to load '{model_short}'. Try a smaller model or free memory."
|
||||
|
||||
return str(error)
|
||||
Reference in New Issue
Block a user