feat: support regex-prefixed ignored upstream models
This commit is contained in:
@@ -3,6 +3,7 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -169,10 +170,7 @@ func collectPendingUpstreamModelChangesFromModels(
|
|||||||
upstreamSet[modelName] = struct{}{}
|
upstreamSet[modelName] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
ignoredSet := make(map[string]struct{})
|
normalizedIgnoredModels := normalizeModelNames(ignoredModels)
|
||||||
for _, modelName := range normalizeModelNames(ignoredModels) {
|
|
||||||
ignoredSet[modelName] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
redirectSourceSet := make(map[string]struct{}, len(modelMapping))
|
redirectSourceSet := make(map[string]struct{}, len(modelMapping))
|
||||||
redirectTargetSet := make(map[string]struct{}, len(modelMapping))
|
redirectTargetSet := make(map[string]struct{}, len(modelMapping))
|
||||||
@@ -193,7 +191,13 @@ func collectPendingUpstreamModelChangesFromModels(
|
|||||||
if _, ok := coveredUpstreamSet[modelName]; ok {
|
if _, ok := coveredUpstreamSet[modelName]; ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if _, ok := ignoredSet[modelName]; ok {
|
if lo.ContainsBy(normalizedIgnoredModels, func(ignoredModel string) bool {
|
||||||
|
if regexBody, ok := strings.CutPrefix(ignoredModel, "regex:"); ok {
|
||||||
|
matched, err := regexp.MatchString(strings.TrimSpace(regexBody), modelName)
|
||||||
|
return err == nil && matched
|
||||||
|
}
|
||||||
|
return ignoredModel == modelName
|
||||||
|
}) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -111,6 +111,18 @@ func TestCollectPendingUpstreamModelChangesFromModels_WithModelMapping(t *testin
|
|||||||
require.Equal(t, []string{"stale-model"}, pendingRemoveModels)
|
require.Equal(t, []string{"stale-model"}, pendingRemoveModels)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCollectPendingUpstreamModelChangesFromModels_WithIgnoredRegexPatterns(t *testing.T) {
|
||||||
|
pendingAddModels, pendingRemoveModels := collectPendingUpstreamModelChangesFromModels(
|
||||||
|
[]string{"gpt-4o"},
|
||||||
|
[]string{"gpt-4o", "claude-3-5-sonnet", "sora-video", "gpt-4.1"},
|
||||||
|
[]string{"regex:^sora-.*$", "gpt-4.1"},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
require.Equal(t, []string{"claude-3-5-sonnet"}, pendingAddModels)
|
||||||
|
require.Equal(t, []string{}, pendingRemoveModels)
|
||||||
|
}
|
||||||
|
|
||||||
func TestBuildUpstreamModelUpdateTaskNotificationContent_OmitOverflowDetails(t *testing.T) {
|
func TestBuildUpstreamModelUpdateTaskNotificationContent_OmitOverflowDetails(t *testing.T) {
|
||||||
channelSummaries := make([]upstreamModelUpdateChannelSummary, 0, 12)
|
channelSummaries := make([]upstreamModelUpdateChannelSummary, 0, 12)
|
||||||
for i := 0; i < 12; i++ {
|
for i := 0; i < 12; i++ {
|
||||||
|
|||||||
@@ -3294,7 +3294,12 @@ const EditChannelModal = (props) => {
|
|||||||
<Form.Input
|
<Form.Input
|
||||||
field='upstream_model_update_ignored_models'
|
field='upstream_model_update_ignored_models'
|
||||||
label={t('已忽略模型')}
|
label={t('已忽略模型')}
|
||||||
placeholder={t('例如:gpt-4.1-nano,gpt-4o-mini')}
|
placeholder={t(
|
||||||
|
'例如:gpt-4.1-nano,regex:^claude-.*$,regex:^sora-.*$',
|
||||||
|
)}
|
||||||
|
extraText={t(
|
||||||
|
'支持精确匹配;使用 regex: 开头可按正则匹配。',
|
||||||
|
)}
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
handleInputChange(
|
handleInputChange(
|
||||||
'upstream_model_update_ignored_models',
|
'upstream_model_update_ignored_models',
|
||||||
|
|||||||
4
web/src/i18n/locales/en.json
vendored
4
web/src/i18n/locales/en.json
vendored
@@ -3337,6 +3337,8 @@
|
|||||||
"输入价格:{{symbol}}{{price}} / 1M tokens": "Input Price: {{symbol}}{{price}} / 1M tokens",
|
"输入价格:{{symbol}}{{price}} / 1M tokens": "Input Price: {{symbol}}{{price}} / 1M tokens",
|
||||||
"输出价格 {{symbol}}{{price}} / 1M tokens": "Output Price {{symbol}}{{price}} / 1M tokens",
|
"输出价格 {{symbol}}{{price}} / 1M tokens": "Output Price {{symbol}}{{price}} / 1M tokens",
|
||||||
"输出价格:{{symbol}}{{price}} / 1M tokens": "Output Price: {{symbol}}{{price}} / 1M tokens",
|
"输出价格:{{symbol}}{{price}} / 1M tokens": "Output Price: {{symbol}}{{price}} / 1M tokens",
|
||||||
"输出价格:{{symbol}}{{total}} / 1M tokens": "Output Price: {{symbol}}{{total}} / 1M tokens"
|
"输出价格:{{symbol}}{{total}} / 1M tokens": "Output Price: {{symbol}}{{total}} / 1M tokens",
|
||||||
|
"例如:gpt-4.1-nano,regex:^claude-.*$,regex:^sora-.*$": "Example: gpt-4.1-nano,regex:^claude-.*$,regex:^sora-.*$",
|
||||||
|
"支持精确匹配;使用 regex: 开头可按正则匹配。": "Supports exact matching. Use a regex: prefix for regex matching."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user