diff --git a/server/internal/api/admin_models.go b/server/internal/api/admin_models.go index 234151e..717aaa1 100644 --- a/server/internal/api/admin_models.go +++ b/server/internal/api/admin_models.go @@ -45,19 +45,22 @@ func (h *Handler) AdminModels(c *gin.Context) { }) } - // 渠道提供了但目录中缺失的模型(孤儿绑定,数据不一致时出现) + // 渠道选中但目录中缺失的模型(孤儿绑定:渠道绑定指向已被删除的模型) var orphans []struct { - ChannelName string - ModelID uint64 + ChannelName string + UpstreamModel string + ModelID uint64 } - h.a.DB.Raw(`SELECT c.name as channel_name, b.model_id + h.a.DB.Raw(`SELECT c.name as channel_name, b.model_id, b.upstream_model FROM channel_model_bindings b LEFT JOIN models m ON m.id = b.model_id LEFT JOIN channels c ON c.id = b.channel_id WHERE m.id IS NULL`).Scan(&orphans) missing := make([]gin.H, 0, len(orphans)) for _, o := range orphans { - missing = append(missing, gin.H{"channel": o.ChannelName, "model_id": o.ModelID}) + missing = append(missing, gin.H{ + "channel": o.ChannelName, "model_id": o.ModelID, "upstream_model": o.UpstreamModel, + }) } // 在用但未定价的模型数(渠道已提供、需定价) @@ -210,6 +213,29 @@ func (h *Handler) AdminDeleteModel(c *gin.Context) { resp.OK(c, gin.H{"ok": true}) } +// AdminDeleteUnusedModels DELETE /api/v1/admin/models/unused — 一键清除未绑定任何渠道的模型。 +// 这些通常是渠道抽屉里选中过、后来又取消绑定留下的目录条目,客户端无法调用。 +func (h *Handler) AdminDeleteUnusedModels(c *gin.Context) { + var orphans []store.Model + if err := h.a.DB.Where("id NOT IN (SELECT DISTINCT model_id FROM channel_model_bindings)").Find(&orphans).Error; err != nil { + resp.Fail(c, http.StatusInternalServerError, "failed to load models") + return + } + names := make([]string, 0, len(orphans)) + ids := make([]uint64, 0, len(orphans)) + for _, m := range orphans { + names = append(names, m.Name) + ids = append(ids, m.ID) + } + if len(ids) > 0 { + if err := h.a.DB.Delete(&store.Model{}, ids).Error; err != nil { + resp.Fail(c, http.StatusInternalServerError, "failed to delete models") + return + } + } + resp.OK(c, gin.H{"deleted": names, "count": len(names)}) +} + // AdminCreateModelBinding POST /api/v1/admin/models/:id/bindings func (h *Handler) AdminCreateModelBinding(c *gin.Context) { modelID, err := strconv.ParseUint(c.Param("id"), 10, 64) diff --git a/web/src/types.ts b/web/src/types.ts index 669a030..c772520 100644 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -74,7 +74,7 @@ export interface Model { export interface ModelSummary { total: number unpriced: number - missing: { channel: string; model_id: number }[] + missing: { channel: string; model_id: number; upstream_model: string }[] denied_count: number } diff --git a/web/src/views/admin/ModelsView.vue b/web/src/views/admin/ModelsView.vue index 9625575..4d19080 100644 --- a/web/src/views/admin/ModelsView.vue +++ b/web/src/views/admin/ModelsView.vue @@ -1,31 +1,49 @@ @@ -140,7 +126,7 @@ onMounted(load)

模型与定价

接口导入不全时可直接输入模型名添加,如 glm-4.7-flash

-
+
+
- +
-

以下渠道提供了未纳入定价的模型

+

以下渠道选中的模型不在定价目录

- {{ x.channel }} → 模型 id#{{ x.model_id }}(请在下方添加并定价) + {{ x.channel }} → {{ x.upstream_model || '模型 #' + x.model_id }}(请到渠道抽屉重新选中,或手动添加)

- 有 {{ summary.unpriced }} 个在用模型未定价,网关将按示例价计费 + 有 {{ summary.unpriced }} 个渠道允许的模型未定价,网关将按示例价计费

-

已启用渠道提供的全部模型均已纳入定价

+

定价目录中渠道允许的模型均已定价

-
+
{{ m.name }} + 渠道允许 + 悬空 {{ m.enabled ? '启用' : '停用' }} 已禁止 未定价 @@ -178,26 +176,25 @@ onMounted(load) 缓存读 {{ m.cache_read_price }}
-
+

允许渠道(渠道抽屉中管理)

{{ b.channel_name }} → {{ b.upstream_model }} -
-

- 未绑定渠道,客户端无法调用该模型 +

+ 悬空模型:无任何渠道提供,客户端无法调用

@@ -222,24 +219,5 @@ onMounted(load) - - - -
-

模型 {{ bindModel?.name }} 通过以下渠道提供

- - - -
- -