🚀 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.
This commit is contained in:
@@ -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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,17 +118,21 @@ 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) {
|
||||||
|
if _, exists := metaMap[pricingModel.Model]; !exists {
|
||||||
metaMap[pricingModel.Model] = m
|
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) {
|
||||||
|
if _, exists := metaMap[pricingModel.Model]; !exists {
|
||||||
metaMap[pricingModel.Model] = m
|
metaMap[pricingModel.Model] = m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for _, m := range containsList {
|
for _, m := range containsList {
|
||||||
for _, pricingModel := range enableAbilities {
|
for _, pricingModel := range enableAbilities {
|
||||||
if strings.Contains(pricingModel.Model, m.ModelName) {
|
if strings.Contains(pricingModel.Model, m.ModelName) {
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user