"""设置路由:查询/修改运行时可调参数。 config.yaml 是只读挂载,改它需重启容器。本路由把部分参数(batch_size 等) 存到 DB 的 setting 表,通过 config.save_setting() + reload_settings() 实现 运行时热更新:保存后清 lru_cache,后续任务读到新值。 当前可调项与 config._OVERIDEABLE_FIELDS 对齐。 """ from __future__ import annotations import logging from fastapi import APIRouter from pydantic import BaseModel, Field from ..config import _OVERIDEABLE_FIELDS, get_settings, save_setting logger = logging.getLogger("audio2text.settings") router = APIRouter(prefix="/api/settings", tags=["settings"]) # ---------------- 响应 / 请求 DTO ---------------- class SettingsResponse(BaseModel): """当前生效的设置值(YAML 基础 + DB 覆盖后的合并值)。""" asr_batch_size: int asr_beam_size: int translation_batch_size: int translation_sort_by_length: bool # 不可改但展示的只读信息 asr_model: str asr_device: str asr_compute_type: str translation_model: str translation_device: str class SettingsUpdate(BaseModel): """设置更新请求:只传要改的字段,未传的保持不变。""" asr_batch_size: int | None = Field(default=None, ge=1, le=128) asr_beam_size: int | None = Field(default=None, ge=1, le=10) translation_batch_size: int | None = Field(default=None, ge=1, le=256) translation_sort_by_length: bool | None = None # ---------------- 字段映射:DTO 字段名 -> config 点分路径 ---------------- _FIELD_MAP: dict[str, str] = { "asr_batch_size": "asr.batch_size", "asr_beam_size": "asr.beam_size", "translation_batch_size": "translation.batch_size", "translation_sort_by_length": "translation.sort_by_length", } # ---------------- 接口 ---------------- @router.get("", summary="查询当前生效的设置") def get_current_settings() -> SettingsResponse: """返回当前生效的设置(YAML 基础 + DB 覆盖合并后的值)。""" s = get_settings() return SettingsResponse( asr_batch_size=s.asr.batch_size, asr_beam_size=s.asr.beam_size, translation_batch_size=s.translation.batch_size, translation_sort_by_length=s.translation.sort_by_length, asr_model=s.asr.model, asr_device=s.asr.device, asr_compute_type=s.asr.compute_type, translation_model=s.translation.model, translation_device=s.translation.device, ) @router.put("", summary="更新设置(保存后对后续任务生效)") def update_settings(req: SettingsUpdate) -> dict: """保存修改的设置项到 DB,清配置缓存。 只处理请求中非 None 的字段。保存后立即生效(后续任务读到新值), 已在跑的任务不受影响(任务在各阶段开始时读配置)。 """ changed: dict = {} for field, path in _FIELD_MAP.items(): val = getattr(req, field) if val is not None: save_setting(path, val) changed[field] = val logger.info("设置已更新:%s = %s(对后续任务生效)", path, val) if not changed: return {"status": "no_change", "changed": {}} return {"status": "saved", "changed": changed}