主要变更: - 移除Hermes智能体及相关回调服务 - 新增知识库RAG、同步、调度、规范化和索引任务服务 - 重构orchestrator服务,增强运行时聊天功能 - 更新前端聊天、政策制度、设置等页面样式和逻辑 - 更新expense_claims和document_intelligence服务 - 删除llm_wiki相关服务和测试文件 - 更新docker-compose配置和启动脚本
127 lines
4.1 KiB
Python
127 lines
4.1 KiB
Python
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 as get_runtime_settings
|
|
from app.schemas.common import ErrorResponse
|
|
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(description="Hermes 读取运行时模型配置时使用的 Bearer Token。"),
|
|
] = None,
|
|
) -> None:
|
|
configured_token = str(get_runtime_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,
|
|
summary="读取系统设置",
|
|
description="返回公司、管理员、模型、日志、邮件和 ONLYOFFICE 的设置快照。",
|
|
)
|
|
def get_settings(db: DbSession) -> SettingsRead:
|
|
return SettingsService(db).get_settings_snapshot()
|
|
|
|
|
|
@router.put(
|
|
"",
|
|
response_model=SettingsRead,
|
|
summary="保存系统设置",
|
|
description="保存系统设置,并同步运行时模型配置与 Hermes 使用的模型路由。",
|
|
responses={
|
|
status.HTTP_400_BAD_REQUEST: {
|
|
"model": ErrorResponse,
|
|
"description": "设置字段校验失败。",
|
|
}
|
|
},
|
|
)
|
|
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,
|
|
summary="测试模型连通性",
|
|
description="验证指定模型服务端点是否可用;当未传 API Key 且提供 slot 时会尝试复用已保存密钥。",
|
|
)
|
|
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)],
|
|
summary="读取 Hermes 运行时模型配置",
|
|
description="供 Hermes 进程读取主模型、备用模型、Embedding 或 Reranker 模型的运行时配置。",
|
|
responses={
|
|
status.HTTP_401_UNAUTHORIZED: {
|
|
"model": ErrorResponse,
|
|
"description": "Hermes 令牌校验失败。",
|
|
},
|
|
status.HTTP_404_NOT_FOUND: {
|
|
"model": ErrorResponse,
|
|
"description": "指定模型槽位不存在。",
|
|
},
|
|
status.HTTP_503_SERVICE_UNAVAILABLE: {
|
|
"model": ErrorResponse,
|
|
"description": "Hermes 集成令牌尚未配置。",
|
|
},
|
|
},
|
|
)
|
|
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)
|