e93507a09c
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
120 lines
3.7 KiB
Python
120 lines
3.7 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
|
|
|
from __future__ import annotations
|
|
|
|
import base64
|
|
import io
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
def _pil_to_preview_payload(image: Any) -> dict[str, Any]:
|
|
buffer = io.BytesIO()
|
|
image.convert("RGB").save(buffer, format = "JPEG", quality = 85)
|
|
return {
|
|
"type": "image",
|
|
"mime": "image/jpeg",
|
|
"width": image.width,
|
|
"height": image.height,
|
|
"data": base64.b64encode(buffer.getvalue()).decode("ascii"),
|
|
}
|
|
|
|
|
|
def _open_pil_image_from_bytes(raw_bytes: bytes):
|
|
from PIL import Image # type: ignore
|
|
with Image.open(io.BytesIO(raw_bytes)) as image:
|
|
return image.copy()
|
|
|
|
|
|
def _to_pil_from_hf_image_dict(value: Any) -> Any | None:
|
|
if not isinstance(value, dict):
|
|
return None
|
|
|
|
raw_bytes = value.get("bytes")
|
|
if isinstance(raw_bytes, (bytes, bytearray)) and len(raw_bytes) > 0:
|
|
try:
|
|
return _open_pil_image_from_bytes(bytes(raw_bytes))
|
|
except (OSError, ValueError):
|
|
pass
|
|
if (
|
|
isinstance(raw_bytes, list)
|
|
and len(raw_bytes) > 0
|
|
and all(isinstance(item, int) and 0 <= item <= 255 for item in raw_bytes)
|
|
):
|
|
try:
|
|
return _open_pil_image_from_bytes(bytes(raw_bytes))
|
|
except (OSError, ValueError):
|
|
pass
|
|
|
|
path_value = value.get("path")
|
|
if isinstance(path_value, str) and path_value.strip():
|
|
try:
|
|
from PIL import Image # type: ignore
|
|
with Image.open(Path(path_value)) as image:
|
|
return image.copy()
|
|
except (OSError, ValueError, TypeError):
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
def to_jsonable(value: Any) -> Any:
|
|
"""Convert numpy/pandas-ish values into plain JSON-safe values."""
|
|
try:
|
|
import numpy as np # type: ignore
|
|
except ImportError: # pragma: no cover
|
|
np = None # type: ignore
|
|
|
|
if np is not None:
|
|
if isinstance(value, np.ndarray):
|
|
return value.tolist()
|
|
if isinstance(value, np.generic):
|
|
return value.item()
|
|
|
|
if isinstance(value, dict):
|
|
return {str(k): to_jsonable(v) for k, v in value.items()}
|
|
if isinstance(value, (list, tuple, set)):
|
|
return [to_jsonable(v) for v in value]
|
|
|
|
if hasattr(value, "isoformat") and callable(value.isoformat):
|
|
try:
|
|
return value.isoformat()
|
|
except (TypeError, ValueError):
|
|
return value
|
|
|
|
return value
|
|
|
|
|
|
def _to_preview_image_payload(value: Any) -> dict[str, Any] | None:
|
|
try:
|
|
from PIL.Image import Image as PILImage # type: ignore
|
|
except ImportError: # pragma: no cover
|
|
return None
|
|
|
|
if not isinstance(value, PILImage):
|
|
hf_image = _to_pil_from_hf_image_dict(value)
|
|
if hf_image is None:
|
|
return None
|
|
value = hf_image
|
|
|
|
return _pil_to_preview_payload(value)
|
|
|
|
|
|
def to_preview_jsonable(value: Any) -> Any:
|
|
"""Convert values into JSON-safe preview values, including PIL images."""
|
|
image_payload = _to_preview_image_payload(value)
|
|
if image_payload is not None:
|
|
return image_payload
|
|
|
|
converted = to_jsonable(value)
|
|
if converted is None or isinstance(converted, (str, int, float, bool)):
|
|
return converted
|
|
if isinstance(converted, dict):
|
|
return {str(k): to_preview_jsonable(v) for k, v in converted.items()}
|
|
if isinstance(converted, (list, tuple, set)):
|
|
return [to_preview_jsonable(v) for v in converted]
|
|
if isinstance(converted, (bytes, bytearray)):
|
|
return base64.b64encode(bytes(converted)).decode("ascii")
|
|
return str(converted)
|