mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 18:25:26 -04:00
fix: detect HuggingFace token when downloading cookbook models (#3459)
Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com>
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
"""cookbook_helpers.py — validators + small helpers shared by the cookbook routes.
|
||||
Extracted from cookbook_routes.py; the routes module imports the symbols it needs."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import ntpath
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import shlex
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import HTTPException
|
||||
from pydantic import BaseModel
|
||||
@@ -90,6 +92,24 @@ def _validate_token(v: str | None) -> str | None:
|
||||
return v
|
||||
|
||||
|
||||
def load_stored_hf_token(*, state_path: Path | str | None = None) -> str:
|
||||
"""Return the decrypted HF token from cookbook_state.json, else env fallback."""
|
||||
path = Path(state_path) if state_path else Path(os.environ.get("DATA_DIR", "data")) / "cookbook_state.json"
|
||||
token = ""
|
||||
if path.exists():
|
||||
try:
|
||||
state = json.loads(path.read_text(encoding="utf-8"))
|
||||
env = state.get("env") if isinstance(state, dict) else {}
|
||||
if isinstance(env, dict) and env.get("hfToken"):
|
||||
from src.secret_storage import decrypt
|
||||
token = decrypt(env.get("hfToken") or "")
|
||||
except Exception:
|
||||
token = ""
|
||||
if not token:
|
||||
token = (os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN") or "").strip()
|
||||
return token
|
||||
|
||||
|
||||
def _validate_local_dir(v: str | None) -> str | None:
|
||||
if v is None or v == "":
|
||||
return None
|
||||
|
||||
@@ -40,6 +40,10 @@ from routes.cookbook_helpers import (
|
||||
_ps_squote, _bash_squote, _validate_serve_cmd, _parse_serve_phase,
|
||||
_safe_env_prefix, _local_tooling_path_export, _append_serve_preflight_exit_lines,
|
||||
_append_serve_exit_code_lines, _append_llama_cpp_linux_accel_build_lines, _cached_model_scan_script,
|
||||
load_stored_hf_token,
|
||||
_append_vllm_linux_preflight_lines, _ollama_bind_from_cmd, _pip_install_fallback_chain,
|
||||
_pip_install_no_cache, _user_shell_path_bootstrap, _venv_safe_local_pip_install_cmd,
|
||||
_diagnose_serve_output, run_ssh_command_async,
|
||||
_ollama_bind_from_cmd, _pip_install_fallback_chain, _pip_install_no_cache,
|
||||
_user_shell_path_bootstrap, _venv_safe_local_pip_install_cmd,
|
||||
ModelDownloadRequest, ServeRequest,
|
||||
@@ -234,14 +238,7 @@ def setup_cookbook_routes() -> APIRouter:
|
||||
return state
|
||||
|
||||
def _load_stored_hf_token() -> str:
|
||||
if not _cookbook_state_path.exists():
|
||||
return ""
|
||||
try:
|
||||
state = json.loads(_cookbook_state_path.read_text(encoding="utf-8"))
|
||||
env = state.get("env") if isinstance(state, dict) else {}
|
||||
return _decrypt_secret(env.get("hfToken") if isinstance(env, dict) else "")
|
||||
except Exception:
|
||||
return ""
|
||||
return load_stored_hf_token(state_path=_cookbook_state_path)
|
||||
|
||||
def _cookbook_ssh_dir() -> Path:
|
||||
# The Docker image keeps cookbook keys under /app/.ssh; that path only
|
||||
|
||||
@@ -2054,13 +2054,14 @@ async def _cookbook_env_for_host(host: str) -> Dict[str, Any]:
|
||||
else:
|
||||
env_prefix = f'eval "$(conda shell.bash hook)" && conda activate {env_path}'
|
||||
|
||||
from routes.cookbook_helpers import load_stored_hf_token
|
||||
return {
|
||||
"env_prefix": env_prefix,
|
||||
"env_type": env_kind,
|
||||
"env_path": env_path,
|
||||
"gpus": env_root.get("gpus") or "",
|
||||
"platform": platform,
|
||||
"hf_token": env_root.get("hfToken") or "",
|
||||
"hf_token": load_stored_hf_token(),
|
||||
"ssh_port": ssh_port,
|
||||
}
|
||||
|
||||
|
||||
@@ -1506,12 +1506,10 @@ export function _hwfitInit() {
|
||||
clearTimeout(_hwfitDebounce);
|
||||
_hwfitDebounce = setTimeout(() => _hwfitFetch(), 400);
|
||||
});
|
||||
// HF Token
|
||||
const hfToken = document.getElementById('hwfit-hftoken');
|
||||
if (hfToken) {
|
||||
hfToken.addEventListener('change', () => { _envState.hfToken = hfToken.value.trim(); _persistEnvState(); });
|
||||
hfToken.addEventListener('input', () => { _envState.hfToken = hfToken.value.trim(); });
|
||||
}
|
||||
// HF token save is owned by cookbook.js (_wireTabEvents) — do not wire a
|
||||
// second change/input handler here. The old duplicate ran after cookbook.js
|
||||
// cleared the input on save and overwrote _envState.hfToken with "", so the
|
||||
// debounced state sync never persisted the token to cookbook_state.json.
|
||||
|
||||
// Rebuild all server select dropdowns with current servers
|
||||
function _rebuildServerSelect() {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Cookbook HF token persistence and lookup."""
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from routes.cookbook_helpers import load_stored_hf_token
|
||||
from src.secret_storage import encrypt
|
||||
|
||||
|
||||
def test_load_stored_hf_token_reads_encrypted_state(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("DATA_DIR", str(tmp_path))
|
||||
state_path = tmp_path / "cookbook_state.json"
|
||||
state_path.write_text(
|
||||
json.dumps({"env": {"hfToken": encrypt("hf_test_token_12345")}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
assert load_stored_hf_token() == "hf_test_token_12345"
|
||||
assert load_stored_hf_token(state_path=state_path) == "hf_test_token_12345"
|
||||
|
||||
|
||||
def test_load_stored_hf_token_falls_back_to_env_when_state_missing(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("DATA_DIR", str(tmp_path))
|
||||
monkeypatch.setenv("HF_TOKEN", "hf_from_env")
|
||||
assert load_stored_hf_token() == "hf_from_env"
|
||||
|
||||
|
||||
def test_load_stored_hf_token_prefers_state_over_env(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("DATA_DIR", str(tmp_path))
|
||||
monkeypatch.setenv("HF_TOKEN", "hf_from_env")
|
||||
state_path = tmp_path / "cookbook_state.json"
|
||||
state_path.write_text(
|
||||
json.dumps({"env": {"hfToken": encrypt("hf_from_state")}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
assert load_stored_hf_token() == "hf_from_state"
|
||||
Reference in New Issue
Block a user