from __future__ import annotations from typing import Annotated from fastapi import APIRouter, Depends, Header, HTTPException, status from sqlalchemy.orm import Session from app.api.deps import get_db from app.core.config import get_settings from app.schemas.settings import ( ModelConnectivityTestRead, ModelConnectivityTestRequest, RuntimeModelConfigRead, SettingsRead, SettingsWrite, ) from app.services.model_connectivity import probe_model_connectivity from app.services.settings import SettingsService router = APIRouter(prefix="/settings") DbSession = Annotated[Session, Depends(get_db)] def require_hermes_agent_token( authorization: Annotated[str | None, Header()] = None, ) -> None: configured_token = str(get_settings().hermes_agent_shared_token or "").strip() if not configured_token: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Hermes 集成令牌未配置。", ) normalized = str(authorization or "").strip() expected = f"Bearer {configured_token}" if normalized != expected: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Hermes 集成鉴权失败。", ) @router.get("", response_model=SettingsRead) def get_settings(db: DbSession) -> SettingsRead: return SettingsService(db).get_settings_snapshot() @router.put("", response_model=SettingsRead) def update_settings(payload: SettingsWrite, db: DbSession) -> SettingsRead: try: return SettingsService(db).save_settings_snapshot(payload) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc @router.post("/model-connectivity", response_model=ModelConnectivityTestRead) def test_model_connectivity(payload: ModelConnectivityTestRequest, db: DbSession) -> ModelConnectivityTestRead: resolved_payload = payload if not payload.api_key and payload.slot: stored_api_key = SettingsService(db).load_saved_model_api_key(payload.slot) if stored_api_key: resolved_payload = payload.model_copy(update={"api_key": stored_api_key}) return probe_model_connectivity(resolved_payload) @router.get( "/runtime-models/{slot}", response_model=RuntimeModelConfigRead, dependencies=[Depends(require_hermes_agent_token)], ) def get_runtime_model_config( slot: str, db: DbSession, ) -> RuntimeModelConfigRead: try: payload = SettingsService(db).get_runtime_model_config(slot) except ValueError as exc: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc return RuntimeModelConfigRead(**payload)