"""用户 AI 接口配置。api_key 用 Fernet 加密存储,不回显明文。""" from fastapi import APIRouter, Depends from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.db import get_db from app.deps import get_current_user from app.models.user import User, UserSettings from app.schemas.settings import SettingsOut, SettingsUpdate from app.services import crypto router = APIRouter(prefix="/api/settings", tags=["settings"]) async def _get_or_create(db: AsyncSession, user_id: str) -> UserSettings: row = await db.scalar( select(UserSettings).where(UserSettings.user_id == user_id) ) if row is None: row = UserSettings(user_id=user_id) db.add(row) await db.flush() return row def _to_out(s: UserSettings) -> SettingsOut: return SettingsOut( llm_base_url=s.llm_base_url, llm_text_model=s.llm_text_model, llm_vision_model=s.llm_vision_model, has_api_key=bool(s.llm_api_key_encrypted), ) @router.get("", response_model=SettingsOut) async def get_settings( db: AsyncSession = Depends(get_db), current: User = Depends(get_current_user), ): s = await _get_or_create(db, current.id) await db.commit() return _to_out(s) @router.put("", response_model=SettingsOut) async def update_settings( payload: SettingsUpdate, db: AsyncSession = Depends(get_db), current: User = Depends(get_current_user), ): s = await _get_or_create(db, current.id) data = payload.model_dump(exclude_unset=True) for field in ("llm_base_url", "llm_text_model", "llm_vision_model"): if field in data: setattr(s, field, data[field]) # api_key:显式传非空值才更新;传空字符串表示清除 if "api_key" in data: if payload.api_key: s.llm_api_key_encrypted = crypto.encrypt(payload.api_key) elif payload.api_key == "": s.llm_api_key_encrypted = None await db.commit() await db.refresh(s) return _to_out(s)