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 4 months ago
parent
commit
327a0ca323

+ 3 - 5
controller/model_meta.go

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

+ 13 - 5
model/pricing.go

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

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

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