设置页AI Tab:网关设置入库、保险丝改维度与grok工具注入
CI / test (push) Successful in 33s

This commit is contained in:
2026-07-16 12:31:36 +08:00
parent 99b551401e
commit da7b29d2e3
11 changed files with 600 additions and 38 deletions
+57 -5
View File
@@ -422,9 +422,47 @@ func aiPathID(c *gin.Context) (uint, bool) {
return uint(id), true
}
// modelCatalog 返回启用渠道聚合去重后的模型目录(含能力),黑名单添加弹窗用。
//
// @Summary 聚合模型目录
// @Tags AI 管理
// @Success 200 {object} itemsResponse[service.AggregatedModel]
// @Security BearerAuth
// @Router /api/v1/ai-model-catalog [get]
func (h *aiAdminHandler) modelCatalog(c *gin.Context) {
items, err := h.gw.AggregatedModels(c.Request.Context())
if err != nil {
respondError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"items": items})
}
// aiSettingsResponse 是 AI 网关全局设置(文档与响应共用)。
type aiSettingsResponse struct {
// FilterDeprecated 开启后已宣布弃用(即使未退役)的模型从列表与路由中排除
FilterDeprecated bool `json:"filterDeprecated"`
// StreamGuardEnabled / StreamGuardKB 是 Responses 流式保险丝:
// instructions+tools 合计超阈值(KB)的流式请求改非流式上游并合成 SSE
StreamGuardEnabled bool `json:"streamGuardEnabled"`
StreamGuardKB int `json:"streamGuardKB"`
// GrokWebSearch / GrokXSearch 是 xai. 模型服务端搜索工具默认注入开关;
// 请求 tools 已包含同名工具时不覆盖
GrokWebSearch bool `json:"grokWebSearch"`
GrokXSearch bool `json:"grokXSearch"`
}
// currentAiSettings 汇总网关运行时设置为响应体。
func (h *aiAdminHandler) currentAiSettings() aiSettingsResponse {
guardOn, guardKB := h.gw.StreamGuard()
web, x := h.gw.GrokSearch()
return aiSettingsResponse{
FilterDeprecated: h.gw.FilterDeprecated(),
StreamGuardEnabled: guardOn,
StreamGuardKB: guardKB,
GrokWebSearch: web,
GrokXSearch: x,
}
}
// aiSettings 返回 AI 网关全局设置。
@@ -435,15 +473,16 @@ type aiSettingsResponse struct {
// @Security BearerAuth
// @Router /api/v1/ai-settings [get]
func (h *aiAdminHandler) aiSettings(c *gin.Context) {
c.JSON(http.StatusOK, aiSettingsResponse{FilterDeprecated: h.gw.FilterDeprecated()})
c.JSON(http.StatusOK, h.currentAiSettings())
}
// updateAiSettings 更新 AI 网关全局设置(当前仅「过滤弃用模型」开关)。
// updateAiSettings 更新 AI 网关全局设置(过滤弃用/流式保险丝/grok 搜索工具默认注入)。
//
// @Summary 更新 AI 网关全局设置
// @Tags AI 管理
// @Param body body aiSettingsResponse true "开启后已宣布弃用(即使未退役)的模型从列表与路由中排除"
// @Param body body aiSettingsResponse true "全量提交;保险丝阈值限 1..1024 KB"
// @Success 200 {object} aiSettingsResponse
// @Failure 400 {object} map[string]string
// @Security BearerAuth
// @Router /api/v1/ai-settings [put]
func (h *aiAdminHandler) updateAiSettings(c *gin.Context) {
@@ -452,9 +491,22 @@ func (h *aiAdminHandler) updateAiSettings(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := h.gw.SetFilterDeprecated(c.Request.Context(), req.FilterDeprecated); err != nil {
if req.StreamGuardKB < 1 || req.StreamGuardKB > 1024 {
c.JSON(http.StatusBadRequest, gin.H{"error": "streamGuardKB 须在 1..1024"})
return
}
ctx := c.Request.Context()
if err := h.gw.SetFilterDeprecated(ctx, req.FilterDeprecated); err != nil {
respondError(c, err)
return
}
c.JSON(http.StatusOK, aiSettingsResponse{FilterDeprecated: h.gw.FilterDeprecated()})
if err := h.gw.SetStreamGuard(ctx, req.StreamGuardEnabled, req.StreamGuardKB); err != nil {
respondError(c, err)
return
}
if err := h.gw.SetGrokSearch(ctx, req.GrokWebSearch, req.GrokXSearch); err != nil {
respondError(c, err)
return
}
c.JSON(http.StatusOK, h.currentAiSettings())
}