Kaynağa Gözat

🚀 feat: expose “Enabled Groups” for models with real-time refresh

Backend
• model/model_meta.go
  – Added `EnableGroups []string` to Model struct
  – fillModelExtra now populates EnableGroups

• model/model_groups.go
  – New helper `GetModelEnableGroups` (reuses Pricing cache)

• model/pricing_refresh.go
  – Added `RefreshPricing()` to force immediate cache rebuild

• controller/model_meta.go
  – `GetAllModelsMeta` & `SearchModelsMeta` call `model.RefreshPricing()` before querying, ensuring groups / endpoints are up-to-date

Frontend
• ModelsColumnDefs.js
  – Added `renderGroups` util and “可用分组” table column displaying color-coded tags

Result
Admins can now see which user groups can access each model, and any ability/group changes are reflected instantly without the previous 1-minute delay.
t0ng7u 5 ay önce
ebeveyn
işleme
b64c8ea56b

+ 9 - 1
controller/model_meta.go

@@ -12,6 +12,9 @@ import (
 
 // GetAllModelsMeta 获取模型列表(分页)
 func GetAllModelsMeta(c *gin.Context) {
+
+    model.RefreshPricing()
+
     pageInfo := common.GetPageQuery(c)
     modelsMeta, err := model.GetAllModels(pageInfo.GetStartIdx(), pageInfo.GetPageSize())
     if err != nil {
@@ -31,6 +34,9 @@ func GetAllModelsMeta(c *gin.Context) {
 
 // SearchModelsMeta 搜索模型列表
 func SearchModelsMeta(c *gin.Context) {
+
+    model.RefreshPricing()
+
     keyword := c.Query("keyword")
     vendor := c.Query("vendor")
     pageInfo := common.GetPageQuery(c)
@@ -128,7 +134,7 @@ func DeleteModelMeta(c *gin.Context) {
     common.ApiSuccess(c, nil)
 }
 
-// 辅助函数:填充 Endpoints 和 BoundChannels
+// 辅助函数:填充 Endpoints 和 BoundChannels 和 EnableGroups
 func fillModelExtra(m *model.Model) {
     if m.Endpoints == "" {
         eps := model.GetModelSupportEndpointTypes(m.ModelName)
@@ -139,5 +145,7 @@ func fillModelExtra(m *model.Model) {
     if channels, err := model.GetBoundChannels(m.ModelName); err == nil {
         m.BoundChannels = channels
     }
+    // 填充启用分组
+    m.EnableGroups = model.GetModelEnableGroups(m.ModelName)
 
 }

+ 12 - 0
model/model_groups.go

@@ -0,0 +1,12 @@
+package model
+
+// GetModelEnableGroups 返回指定模型名称可用的用户分组列表。
+// 复用缓存的定价映射,避免额外的数据库查询。
+func GetModelEnableGroups(modelName string) []string {
+    for _, p := range GetPricing() {
+        if p.ModelName == modelName {
+            return p.EnableGroup
+        }
+    }
+    return make([]string, 0)
+}

+ 1 - 0
model/model_meta.go

@@ -38,6 +38,7 @@ type Model struct {
     DeletedAt   gorm.DeletedAt `json:"-" gorm:"index"`
 
     BoundChannels []BoundChannel `json:"bound_channels,omitempty" gorm:"-"`
+    EnableGroups []string       `json:"enable_groups,omitempty" gorm:"-"`
 }
 
 // Insert 创建新的模型元数据记录

+ 14 - 0
model/pricing_refresh.go

@@ -0,0 +1,14 @@
+package model
+
+// RefreshPricing 强制立即重新计算与定价相关的缓存。
+// 该方法用于需要最新数据的内部管理 API,
+// 因此会绕过默认的 1 分钟延迟刷新。
+func RefreshPricing() {
+    updatePricingLock.Lock()
+    defer updatePricingLock.Unlock()
+
+    modelSupportEndpointsLock.Lock()
+    defer modelSupportEndpointsLock.Unlock()
+
+    updatePricing()
+}

+ 18 - 0
web/src/components/table/models/ModelsColumnDefs.js

@@ -91,6 +91,19 @@ const renderDescription = (text) => {
   );
 };
 
+// Render groups (enable_groups)
+const renderGroups = (groups) => {
+  if (!groups || groups.length === 0) return '-';
+  return renderLimitedItems({
+    items: groups,
+    renderItem: (g, idx) => (
+      <Tag key={idx} size="small" shape='circle' color={stringToColor(g)}>
+        {g}
+      </Tag>
+    ),
+  });
+};
+
 // Render tags
 const renderTags = (text) => {
   if (!text) return '-';
@@ -232,6 +245,11 @@ export const getModelsColumns = ({
       dataIndex: 'bound_channels',
       render: renderBoundChannels,
     },
+    {
+      title: t('可用分组'),
+      dataIndex: 'enable_groups',
+      render: renderGroups,
+    },
     {
       title: t('创建时间'),
       dataIndex: 'created_time',