Browse Source

🚀 refactor: refine pricing refresh logic & hide disabled models

Summary
-------
1. Pricing generation
   • `model/pricing.go`: skip any model whose `status != 1` when building
     `pricingMap`, ensuring disabled models are never returned to the
     front-end.

2. Cache refresh placement
   • `controller/model_meta.go`
     – Removed `model.RefreshPricing()` from pure read handlers
       (`GetAllModelsMeta`, `SearchModelsMeta`).
     – Kept refresh only in mutating handlers
       (`Create`, `Update`, `Delete`), guaranteeing data is updated
       immediately after an admin change while avoiding redundant work
       on every read.

Result
------
Front-end no longer receives information about disabled models, and
pricing cache refreshes occur exactly when model data is modified,
improving efficiency and consistency.
t0ng7u 10 tháng trước cách đây
mục cha
commit
cfb5b6024c

+ 3 - 5
controller/model_meta.go

@@ -13,8 +13,6 @@ import (
 // GetAllModelsMeta 获取模型列表(分页)
 func GetAllModelsMeta(c *gin.Context) {
 
-    model.RefreshPricing()
-
     pageInfo := common.GetPageQuery(c)
     modelsMeta, err := model.GetAllModels(pageInfo.GetStartIdx(), pageInfo.GetPageSize())
     if err != nil {
@@ -35,8 +33,6 @@ 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)
@@ -87,6 +83,7 @@ func CreateModelMeta(c *gin.Context) {
         common.ApiError(c, err)
         return
     }
+    model.RefreshPricing()
     common.ApiSuccess(c, &m)
 }
 
@@ -116,6 +113,7 @@ func UpdateModelMeta(c *gin.Context) {
             return
         }
     }
+    model.RefreshPricing()
     common.ApiSuccess(c, &m)
 }
 
@@ -131,6 +129,7 @@ func DeleteModelMeta(c *gin.Context) {
         common.ApiError(c, err)
         return
     }
+    model.RefreshPricing()
     common.ApiSuccess(c, nil)
 }
 
@@ -149,5 +148,4 @@ func fillModelExtra(m *model.Model) {
     m.EnableGroups = model.GetModelEnableGroups(m.ModelName)
     // 填充计费类型
     m.QuotaType = model.GetModelQuotaType(m.ModelName)
-
 }

+ 13 - 5
model/pricing.go

@@ -118,15 +118,19 @@ func updatePricing() {
 	for _, m := range prefixList {
 		for _, pricingModel := range enableAbilities {
 			if strings.HasPrefix(pricingModel.Model, m.ModelName) {
-				metaMap[pricingModel.Model] = m
-			}
+                if _, exists := metaMap[pricingModel.Model]; !exists {
+                    metaMap[pricingModel.Model] = m
+                }
+            }
 		}
 	}
 	for _, m := range suffixList {
 		for _, pricingModel := range enableAbilities {
 			if strings.HasSuffix(pricingModel.Model, m.ModelName) {
-				metaMap[pricingModel.Model] = m
-			}
+                if _, exists := metaMap[pricingModel.Model]; !exists {
+                    metaMap[pricingModel.Model] = m
+                }
+            }
 		}
 	}
 	for _, m := range containsList {
@@ -205,8 +209,12 @@ func updatePricing() {
             SupportedEndpointTypes: modelSupportEndpointTypes[model],
         }
 
-        // 补充模型元数据(描述、标签、供应商
+        // 补充模型元数据(描述、标签、供应商、状态
         if meta, ok := metaMap[model]; ok {
+            // 若模型被禁用(status!=1),则直接跳过,不返回给前端
+            if meta.Status != 1 {
+                continue
+            }
             pricing.Description = meta.Description
             pricing.Tags = meta.Tags
             pricing.VendorID = meta.VendorID

+ 4 - 6
web/src/components/table/models/modals/EditModelModal.jsx

@@ -305,7 +305,6 @@ const EditModelModal = (props) => {
                       label={t('模型名称')}
                       placeholder={t('请输入模型名称,如:gpt-4')}
                       rules={[{ required: true, message: t('请输入模型名称') }]}
-                      disabled={isEdit || !!props.editingModel?.model_name}
                       showClear
                     />
                   </Col>
@@ -317,9 +316,8 @@ const EditModelModal = (props) => {
                       placeholder={t('请选择名称匹配类型')}
                       optionList={nameRuleOptions.map(o => ({ label: t(o.label), value: o.value }))}
                       rules={[{ required: true, message: t('请选择名称匹配类型') }]}
-                      disabled={!!props.editingModel?.model_name} // 通过未配置模型过来的禁用选择
-                      style={{ width: '100%' }}
                       extraText={t('根据模型名称和匹配规则查找模型元数据,优先级:精确 > 前缀 > 后缀 > 包含')}
+                      style={{ width: '100%' }}
                     />
                   </Col>
 
@@ -339,13 +337,13 @@ const EditModelModal = (props) => {
                       placeholder={t('选择标签组后将自动填充标签')}
                       optionList={tagGroups.map(g => ({ label: g.name, value: g.id }))}
                       showClear
-                      style={{ width: '100%' }}
                       onChange={(value) => {
                         const g = tagGroups.find(item => item.id === value);
                         if (g && formApiRef.current) {
                           formApiRef.current.setValue('tags', g.items || []);
                         }
                       }}
+                      style={{ width: '100%' }}
                     />
                   </Col>
 
@@ -356,7 +354,6 @@ const EditModelModal = (props) => {
                       placeholder={t('输入标签或使用","分隔多个标签')}
                       addOnBlur
                       showClear
-                      style={{ width: '100%' }}
                       onChange={(newTags) => {
                         if (!formApiRef.current) return;
                         const normalize = (tags) => {
@@ -366,6 +363,7 @@ const EditModelModal = (props) => {
                         const normalized = normalize(newTags);
                         formApiRef.current.setValue('tags', normalized);
                       }}
+                      style={{ width: '100%' }}
                     />
                   </Col>
                 </Row>
@@ -391,13 +389,13 @@ const EditModelModal = (props) => {
                       optionList={vendors.map(v => ({ label: v.name, value: v.id }))}
                       filter
                       showClear
-                      style={{ width: '100%' }}
                       onChange={(value) => {
                         const vendorInfo = vendors.find(v => v.id === value);
                         if (vendorInfo && formApiRef.current) {
                           formApiRef.current.setValue('vendor', vendorInfo.name);
                         }
                       }}
+                      style={{ width: '100%' }}
                     />
                   </Col>
                 </Row>